dojo.provide("parus.templateGridPane");

dojo.require("dojo.window");

dojo.require("dijit.Dialog");
dojo.require("dijit.form.Button");
dojo.require("dijit.layout.BorderContainer");
dojo.require("dijit.layout.TabContainer");
dojo.require("dijit.layout.ContentPane");
dojo.require("dijit.Menu");
dojo.require("dijit.Tooltip");
dojo.require("dijit.TooltipDialog");

dojo.require("dijit.form.NumberTextBox");
dojo.require("dijit.form.DateTextBox");
dojo.require("dijit.form.ValidationTextBox");

dojo.require("parus.parus8");
dojo.require("parus.dialog");
dojo.require("parus.database");
dojo.require("parus.dictEdit");
dojo.require("parus.xml");
dojo.require("parus.balanceRowCountDialog");
dojo.require("parus.balanceIndexConsDialog");
dojo.require("parus.templateGridPaneMixins");
dojo.require("parus.progressDialog");
dojo.require("parus.balanceRemarksDialog");
dojo.require("parus.balanceRemarkDialog");
dojo.require("parus.templateGridPaneSaveLogConfirmation");
dojo.require("parus.balanceZoomDialog");
dojo.require("parus.balanceIndexConsComparation");
dojo.require("parus.balanceIndexConsComparationItem");
dojo.require("parus.balanceIndexConsComparationItems");

dojo.declare("parus.templateGridPane", [dijit.layout.ContentPane], {

  report: null,

  subreport: null,

  template: null,

  kind: null,

  agent: null,

  section: null,

  direction: null,

  editing: null,

  modified: false,

  headingContentPane: null,

  readonly: false,

  reportDate: null,

  formCode: null,

  username: null,

  ignoreWarnings: true,

  _lastClicked: null,

  info: null,

  templateNode: null,

  focusNode: null,

  clipboardNode: null,

  pane: null,

  parentPane: null,

  autonomousMode: false,

  useHistory: null,

  onDone: null,

  returnToPane: null,

  remarksShown: false,

  zoom: 1,

  defaultZoom: 100,

  gutterSize: 0,

  gutterNode: null,

  _gutterLevels: null,

  _forceScrollGutter: false,

  _minTotalLevel: null,

  _maxTotalLevel: null,

  _allValuesLoaded: false,

  _progressIndicator: null,

  _remarksStore: null,

  _logStore: null,

  _logGrid: null,

  _logPane: null,

  moveAfterReturnDirection: 40,

  "class": "balanceTemplateContentPaneContent",

  postCreate: function() {
    this.inherited(arguments);
    this.ioArgs = {
      headers: {
        "Disable-Basic-Auth": "yes",
        "If-None-Match": "none"
      }
    };
  },

  changeZoom: function(dz) {
    if (dz > 0) this.zoom = this.zoom * 1.2
    else if (dz < 0) this.zoom = this.zoom / 1.2
    else this.zoom = 1;
    this._zoomChanged();
  },

  _zoomChanged: function() {
    dojo.style(this.templateNode, {
      zoom: (this.zoom * 100) + "%",
      MozTransform: "scale(" + this.zoom + ")",
      MozTransformOrigin: "0 0"
    });
    if (this.gutterNode) {
      dojo.style(this.gutterNode, {
        zoom: (this.zoom * 100) + "%",
        MozTransform: "scale(" + this.zoom + ")",
        MozTransformOrigin: "0 0"
      });
    }

  },

  _checkConsComparationMenuItem: null,

  _checkConsComparationIcon: function() {
    if (!this._checkConsComparationMenuItem) return;
    if (this._checkConsComparationMenuItem.customIcon != "PCwifiCustomIcon") return;

    var icon = parus.parus8.consComparationData ? "PCwificheckedCustomIcon" : "PCwifiCustomIcon";
    this._checkConsComparationMenuItem.attr("iconClass", icon);
    if (this._checkConsComparationMenuItem.toolBarButton) this._checkConsComparationMenuItem.toolBarButton.attr("iconClass", icon + "Big");
  },

  _layout: function() {
    this._checkConsComparationIcon();
    return this.inherited(arguments);
  },

  progressIndicate: function(message) {
    if (message) {
      if (this._progressIndicator) {
        this._progressIndicator.messageText.innerHTML = message;
      }
      else {
        this._progressIndicator = new parus.progressDialog({
          message: message
        });
        this._progressIndicator.show();
      }
    }
    else {
      if (this._progressIndicator) {
        this._progressIndicator.close();
        this._progressIndicator = null;
      };
    }
  },

  logGrid: function(logNodes) {

    if (!logNodes || logNodes.length == 0) {
      if (this._logPane) {
        this.parentPane.getChildren()[0].removeChild(this._logPane);
        this._logPane.destroyRecursive();
      }
      this._logPane = null;
      this._logGrid = null;
      this._logStore = null;
      return;
    };

    this._logStore = new parus.gridData({
      persistent: true,
      _data: logNodes
    });


    if (this._logGrid) this._logGrid.setStore(this._logStore)
    else {
      var pane = new dijit.layout.ContentPane({
        region: "bottom",
        style: "height:33%",
        preload: true,
        parseOnLoad: false,
        href: dojo.moduleUrl("parus", "templateGridPaneSaveLog.html").toString(),
        onLoad: dojo.hitch(this, function() {


          var parsed = dojo.parser.parse({
            rootNode: pane.domNode,
            template: true
          });

          dojo.forEach(parsed, dojo.hitch(this, function(widget) {
            dojo.mixin(widget, {
              templatePane: this
            });
            var attachPoint = widget.dojoAttachPoint;
            if (attachPoint) pane[attachPoint] = widget;
          }));

          this._logGrid = pane.logGrid;

          pane.logGridPopupMenu.bindDomNode(pane.logGrid.viewsNode);
          pane.closeLogGridMenuItem.onClick = dojo.hitch(this, this.closeLogGrid);
          pane.followLogGridMenuItem.onClick = dojo.hitch(this, this.followLogGrid);
          pane.excelLogGridMenuItem.onClick = dojo.hitch(this, function() {
            parus.balance.exportGrid(this._logGrid, null, null)
          });

          this._logPane = pane;
          this._logGrid.setStore(this._logStore);

        })


      });
      this.parentPane.getChildren()[0].addChild(pane);
      pane.templatePane = this;


    }

    return this._logGrid;

  },

  closeLogGrid: function() {
    if (this._logPane) {
      this.parentPane.getChildren()[0].removeChild(this._logPane);
      this._logPane.destroyRecursive();
    }
    this._logPane = null;
    this._logGrid = null;
    this._logStore = null;
  },

  followLogGrid: function() {
    var grid = this._logGrid;
    var store = grid.store;
    var index = grid.selection.getSelectedIndex();
    var item = grid.getItem(index);

    parus.templateGridPane.followLogMessage(this.id, store.getValue(item, "BALANCEINDEX") || "", store.getValue(item, "TABLE_RN") || "", store.getValue(item, "ROW_NUMB") || "", store.getValue(item, "BLTABLESIND") || "");
  },

  postMixInProperties: function() {
    this.inherited(arguments);
    this.pane = this;
    this.progressIndicate("Загружается трафарет отчета....");
    this.href = parus.database.getTemplateUrl(this.template);
  },

  _monitorChanges: false,
  _changedCells: null,

  setCellText: function(node, valueNode, value) {
    if (!node && !valueNode) return false;
    if (!valueNode) valueNode = this.getValueNode(node);
    if (!node) {
      node = valueNode;
      while (node && !node.getAttribute("cid"))
      node = node.parentNode;
    }

    var newValue = parus.parus8.formatExcelValue(value, node.getAttribute("fmt"), false, node.getAttribute("intpart"), node.getAttribute("fracpart"));

    if (valueNode.innerHTML.toString() == newValue.toString()) return false;

    if (this._monitorChanges && node.getAttribute("wt") && !node.getAttribute("clid")) {

      this._changedCells = this._changedCells || {};
      if (!this._changedCells[node.getAttribute("uid")]) if (newValue != valueNode.innerHTML) this._changedCells[node.getAttribute("uid")] = node;

    }

    valueNode.innerHTML = newValue;

    if (this._allValuesLoaded) if (!(dojo.isIE <= 6)) this.checkCellHeight(node, valueNode, false, null, true);
    this.drawAllCanvas();

    return true;

  },

  _checkCellHeightNode: null,

  checkCellHeight: function(cell, valueNode, deferred, clone, doShiftParts) {
    if (this.direction != "0") return;

    if (!cell) return;

    if (!cell.getAttribute("wt")) return;


    if (!valueNode) valueNode = this.getValueNode(cell);
    var value = parus.parus8.getTextContent(valueNode);

    if (!value) return;

    var c;

    if (clone) c = clone.size
    else if (this.__deferredAttrs) {
      var defs = this.__deferredAttrs[cell.getAttribute("uid")];
      if (defs) {
        if (defs.h) {
          c = defs.h;
        } else {
          c = cell.offsetHeight;
        };
        c += defs.dh;
      } else {
        c = cell.offsetHeight;
      }
    } else {
      c = cell.offsetHeight;
    };


    if (!this._checkCellHeightNode) {

      this._checkCellHeightNode = document.createElement("div");
      dojo.style(this._checkCellHeightNode, {
        overflowY: "visible",
        left: "-10000px",
        top: "-10000px",
        height: "auto",
        position: "absolute"
      });
      document.body.appendChild(this._checkCellHeightNode);
    }

    this._checkCellHeightNode.className = cell.className;
    this._checkCellHeightNode.innerHTML = cell.innerHTML;

    var h = this._checkCellHeightNode.offsetHeight;

    if (h > c) {

      var cellid = (/^R(\d+)C(\d+)$/g).exec(cell.getAttribute("cid"));
      var rowid = Number(cellid[1]);
      var rcnt = Number(cell.getAttribute("rcnt"));
      var pane = this;

      var correctCell = function(cell) {
        var id = (/^R(\d+)C(\d+)$/g).exec(cell.getAttribute("cid"));
        var row = Number(id[1]);
        var rc = Number(cell.getAttribute("rcnt"));

        if ((row < rowid) && (row + rc - 1 >= rowid)) {
          pane.__setDefferedAttr(cell, "dh", h - c);
        }
        else if (row == rowid) {
          if ((rc == rcnt) && h) pane.__setDefferedAttr(cell, "h", h);
          else pane.__setDefferedAttr(cell, "dh", h - c);
        }
        else if (row > rowid) pane.__setDefferedAttr(cell, "dy", h - c);
      };

      var part = (clone) ? clone.part : this._parts[cell.getAttribute("pid")];
      if (part) {

        if (part.table) {

          var table = clone ? clone.table : this._tables.byKey[cell.getAttribute("tid")];

          var clone = clone || table.clones.byKey[cell.getAttribute("clid")];

          if (!clone) dojo.forEach(table.totals, function(total) {
            if (!clone) clone = total.clones.byKey[cell.getAttribute("clid")];
          });

          if (clone) {

            dojo.forEach(clone.cells, correctCell);

            this.__setDefferedAttr(clone.node, "dh", h - clone.size);
            clone.size += (h - c);
            clone.table.offsetSize += (h - c);

            this.shiftClones(table, clone.commonIndex, h - c, deferred);
          }
        }
        else {
          dojo.query("[cid]", part.node).forEach(correctCell);
        }

        if (doShiftParts) this.shiftParts(part, h - c, deferred);
        if (!deferred) this.__fireDefferedAttrs();
      }

    }
  },

  drawAllCanvas: function() {
    if (!this._allValuesLoaded) return;
    if (!this.drawCanvasText) return;

    if (!dojo.isIE || (dojo.isIE >= 10)) {
      dojo.query("canvas", this.containerNode).forEach(dojo.hitch(this, function(node) {
        this.drawCanvasText(node);
      }));
    }
  },

  getValueNode: function(node) {
    return node ? dojo.query("[rid='v']", node)[0] : null;
  },

  saveHistory: function(action) {

    this.progressIndicate("История значений формируется....");

    var values = {
      "VALUES": {
        "INDEXES": [],
        "TABLES": []
      }
    };

    dojo.forEach(this._staticValues, function(staticValue) {

      var text = parus.parus8.getTextContent(staticValue.valueNode);
      (values["VALUES"])["INDEXES"].push({
        "ROW": {
          COL: staticValue.col,
          ROWN: staticValue.row,
          VALUE: text,
          BITYPE: staticValue.dataType
        }
      });

    });


    dojo.forEach(this._tables, function(table) {
      var rows = [];

      dojo.forEach(table.clones, function(clone) {

        dojo.forEach(clone._staticValues, function(staticValue) {

          var text = parus.parus8.getTextContent(staticValue.valueNode);
          (values["VALUES"])["TABLES"].push({
            "ROW": {
              RN: table.rn,
              NUMB: clone.rn,
              INDEXRN: staticValue.balanceIndex,
              TOTAL: null,
              VALUE: text,
              BITYPE: table.indexes.byKey[staticValue.balanceIndex].dataType
            }
          });


        });

      });

      dojo.forEach(table.totals, function(total) {

        dojo.forEach(total.clones, function(clone) {

          dojo.forEach(clone._staticValues, function(staticValue) {

            var text = parus.parus8.getTextContent(staticValue.valueNode);
            (values["VALUES"])["TABLES"].push({
              "ROW": {
                RN: table.rn,
                NUMB: clone.rn,
                INDEXRN: staticValue.balanceIndex,
                TOTAL: total.rn,
                VALUE: text
              }
            });
          });

        });

      });

    });

    this.progressIndicate("История значений сохраняется....");

    parus.database._xhr("storehistory.xml", null, {
      "REPORT": this.report,
      "SUBREPORT": this.subreport,
      "TEMPLATE": this.template,
      "DATA": values
    }, dojo.hitch(this, function(response) {

      this.progressIndicate();
      if (response.documentElement.nodeName == "error") return;
      if (action) action();
    }));

  },

  saveValues: function(ignoreWarnings, action) {

    var values = {
      "VALUES": {
        "INDEXES": [],
        "TABLES": []
      }
    };

    dojo.forEach(this._staticValues, function(staticValue) {
      var text = parus.parus8.getTextContent(staticValue.valueNode);
      var obj = {};
      obj["ID_" + staticValue.balanceIndex] = text;
      (values["VALUES"])["INDEXES"].push(obj);
    });

    var clonesCount = 0;

    dojo.forEach(this._tables, function(table) {
      dojo.forEach(table.clones, function(clone) {
        if (clone.freeClone) clonesCount++;
      })
    });

    if (clonesCount) {
      ids = parus.parus8.nodeField(parus.parus8.rowNodes(parus.database.execute("CreateIdents", {
        COUNT: clonesCount
      }))[0], "clobIDENTS").split(";");
      var i = 0;
      var rs = this._remarksStore._data;

      dojo.forEach(this._tables, function(table) {
        dojo.forEach(table.clones, function(clone) {
          if (clone.freeClone && !clone.uninitialized) {
            var oldRN = clone.rn;
            clone.rn = ids[i];
            delete table.clones.byKey[oldRN];
            table.clones.byKey[clone.rn] = clone;

            dojo.forEach(clone.cells, function(cell) {
              cell.setAttribute("clid", clone.rn);
            });
            dojo.forEach(rs, function(item) {
              if (parus.parus8.nodeField(item, "_NEW") && (item.CLONERN == oldRN)) item.CLONERN = clone.rn;
            });
            clone.freeClone = false;
            i++;
          }
        })
      });
    };

    dojo.forEach(this._tables, function(table) {
      var rows = [];

      dojo.forEach(table.clones, function(clone) {

        if (!clone.uninitialized) {

          var row = [];

          dojo.forEach(clone._staticValues, function(staticValue) {

            var text = parus.parus8.getTextContent(staticValue.valueNode);
            var obj = {};
            obj["TID_" + staticValue.balanceIndex] = text;
            row.push(obj);
          });

          dojo.mixin(row, {
            "NUMB": clone.rn
          });
          rows.push({
            "ROW": row
          });

        }
      });

      dojo.forEach(table.totals, function(total) {

        dojo.forEach(total.clones, function(clone) {

          var row = [];

          dojo.forEach(clone._staticValues, function(staticValue) {
            var text = parus.parus8.getTextContent(staticValue.valueNode);
            var obj = {};
            obj["TID_" + staticValue.balanceIndex] = text;
            row.push(obj);
          });

          dojo.mixin(row, {
            "TOTAL": total.totalkey,
            "NUMB": clone.rn
          });
          rows.push({
            "ROW": row
          });
        });
      });


      var tableObj = {};
      tableObj["T_" + table.rn] = rows;
      (values["VALUES"])["TABLES"].push(tableObj);
    });


    var remarks = {
      "REMARKS": []
    };

    dojo.forEach(this._remarksStore._data, function(item) {
      //if (parus.parus8.nodeField(item, "_NEW"))
      remarks["REMARKS"].push({
        "REMARK": {
          "INDEXRN": parus.parus8.nodeField(item, "INDEXRN"),
          "CLONERN": parus.parus8.nodeField(item, "CLONERN") || null,
          "TABLERN": parus.parus8.nodeField(item, "TABLERN") || null,
          "CHANGE_DATE": parus.parus8.nodeField(item, "CHANGE_DATE"),
          "NOTE": parus.parus8.nodeField(item, "NOTE"),
          "CODE": parus.parus8.nodeField(item, "CODE"),
          "AUTHID": parus.parus8.nodeField(item, "AUTHID") || ''
        }
      })
    });


    this.progressIndicate("Значения сохраняются....");

    parus.database.execute("SaveValues", {
      "REPORT": this.report,
      "SUBREPORT": this.subreport,
      "TEMPLATE": this.template,
      "DATA": values,
      "REMARKS": remarks,
      "IGNORE_WARNINGS": ignoreWarnings ? 1 : 0

    }, dojo.hitch(this, function(response) {

      this.progressIndicate();

      if (response.documentElement.nodeName == "error") return;

      var logRows = parus.parus8.rowNodes(parus.parus8.nodeField(parus.parus8.rowNodes(response)[0], "xmlLOG"));
      var autocalc = parus.parus8.nodeField(parus.parus8.rowNodes(response)[0], "AUTOCALC");
      if (logRows.length == 0) {

        dojo.forEach(this._remarksStore._data, function(item) {
          if (item["_NEW"]) item["_NEW"] = false;
        });

        if (autocalc == "1") {

          this.refreshTemplate().addCallback(dojo.hitch(this, function() {
            if (this._logGrid) this.logGrid([]);
            if (action) action();
            this.modified = false;
            this.onModified();
          }));

        }
        else {

          if (this._logGrid) this.logGrid([]);
          if (action) action();
          this.modified = false;
          this.onModified();
        }
      }
      else {

        var canIgnoreWarnings, optionValue = parus.parus8.optionValue("Balance_CanSaveReportsWithWarnings");

        if (optionValue == "0") canIgnoreWarnings = true;
        else if (optionValue == "1") canIgnoreWarnings = false;
        else canIgnoreWarnings = this.ignoreWarnings;

        new parus.templateGridPaneSaveLogConfirmation({
          message: "При сохранении значений обнаружены нарушения установленных ограничений.",

          ignoreWarnings: dojo.hitch(this, function() {
            this.saveValues(true, action);
          }),

          canIgnoreWarnings: canIgnoreWarnings,

          continueEditing: dojo.hitch(this, function() {
            var newData = parus.parus8.rowNodes(parus.parus8.nodeField(parus.parus8.rowNodes(response)[0], "xmlDATA"));
            var newRemarks = parus.parus8.rowNodes(parus.parus8.nodeField(parus.parus8.rowNodes(response)[0], "xmlREMARKS"));
            if (newData.length > 0) this.loadNewData(newData, newRemarks);
            this.logGrid(logRows);
          })

        }).show();

      }
    }))

  },

  refreshTemplate: function() {
    this.progressIndicate("Загружается трафарет отчета....");
    dojo.empty(this.templateNode);
    if (this.gutterNode) dojo.empty(this.gutterNode);
    this.gutterNode = null;
    this._gutterLevels = null;
    this._minTotalLevel = null;
    this._maxTotalLevel = null;
    this.gutterSize = 0;
    this.title = null;
    this.logGrid([]);
    return this.refresh();
  },


  reload: function() {
    this.performConfirmation(

    dojo.hitch(this, function() {

      dojo.fadeOut({
        node: this.domNode,
        onEnd: dojo.hitch(this, function() {
          this.refreshTemplate();
        })
      }).play();

    }), true);

  },


  _setTemplate: function(template, direction) {
    this.template = template;
    this.direction = direction;
    this.href = parus.database.getTemplateUrl(this.template);
    //    this.title = null;
    this.refreshTemplate();
  },

  _chooseTemplateAction: function() {

    dojo.fadeOut({
      node: this.domNode,
      onEnd: dojo.hitch(this, function() {

        parus.database.query("BalanceReportTemplates", {
          "REPORT": this.report
        }, dojo.hitch(this, function(response) {

          var templates = parus.parus8.rowNodes(response);
          if (templates.length == 0) {
            parus.parus8.errorMessage("Трафареты для редактирования значений отсутствуют или недоступны.");
            return;
          };

          var template;
          var direction;

          if (templates.length == 1) {
            template = parus.parus8.nodeField(templates[0], "RN");
            direction = parus.parus8.nodeField(templates[0], "DIRECT_TABLE");
          }
          else dojo.forEach(templates, function(templateNode) {
            if (parus.parus8.nodeField(templateNode, "EDIT_DEFAULT") == "1") {
              template = parus.parus8.nodeField(templateNode, "RN");
              direction = parus.parus8.nodeField(templateNode, "DIRECT_TABLE");
            }
          });

          if (template) this._setTemplate(template, direction)
          else {

            var dialog = new parus.balanceTemplatesDialog({

              templates: templates,

              onApply: dojo.hitch(this, function() {

                dojo.forEach(dialog.templatesGrid.selection.getSelected(), function(item) {
                  template = dialog.templatesGrid.store.getValue(item, "RN", "");
                  direction = dialog.templatesGrid.store.getValue(item, "DIRECT_TABLE", "")
                });

                return true;
              }),

              onClose: dojo.hitch(this, function() {
                this._setTemplate(template || this.template, direction || this.direction);
              })

            });
            dialog.show();
          }

        }));

      })
    }).play();
  },

  chooseTemplate: function() {
    this.performConfirmation(
    dojo.hitch(this, this._chooseTemplateAction), true);
  },

  _cells: null,

  _staticValues: null,

  _tables: null,

  _parts: null,

  __staticValuesIndex: null,

  splitPart: function(col, row, width, height) {

    if (this.direction == "0") {
      col = 1;
      width = this.cols;
    }
    else {
      row = 1;
      height = this.rows;
    };

    var part = {
      node: document.createElement("div"),
      table: null,
      col: col,
      row: row,
      width: width,
      height: height,
      index: this._parts.length
    };

    var coords = this.cellCoords(col, row, col + width - 1, row + height - 1);

    dojo.style(part.node, {
      width: coords.w + "px",
      height: coords.h + "px",
      left: coords.l + "px",
      top: coords.t + "px",
      margin: 0,
      padding: 0,
      position: "absolute",
      overflow: "hidden"
    });

    part.node.setAttribute("uid", this._cellnums++);

    for (var i = col; i <= col + width - 1; i++)
    for (var j = row; j <= row + height - 1; j++) {
      var id = "R" + j + "C" + i;
      var cell = this._cells[id];
      if (cell) {
        if (coords.t != 0 || coords.l != 0) dojo.style(cell, {
          top: (parus.parus8.styleSize(cell.style.top) - coords.t) + "px",
          left: (parus.parus8.styleSize(cell.style.left) - coords.l) + "px"
        });
        cell.setAttribute("pid", part.index);
        part.node.appendChild(cell);
      };
    };

    dojo.query("*[rid='w']>*[rid='s']", this.templateNode).forEach(function(img) {
      var t = parus.parus8.styleSize(img.style.top);
      var l = parus.parus8.styleSize(img.style.left);
      if ((coords.t <= t) && (coords.t + coords.h >= t) && (coords.l <= l) && (coords.l + coords.w >= l)) {
        part.node.appendChild(img);
        dojo.style(img, {
          left: (l - coords.l) + "px",
          top: (t - coords.t) + "px"
        });
      }
    });

    this.templateNode.appendChild(part.node);
    this._parts.push(part);
    return part;
  },

  _focusNodeConnection: null,

  selectCell: function(cell, persist) {
    if (this.editing) return;
    if (!cell) return;
    if (cell.target) cell = cell.target;
    while (cell && !cell.getAttribute("cid"))
    cell = cell.parentNode;

    if (!cell) return;
    if (this._lastClicked == cell) return;
    dojo.query(".templateGridSelectedCellBk", this.templateNode).removeClass("templateGridSelectedCellBk");
    dojo.query(".templateGridSelectedCellBorder", this.templateNode).removeClass("templateGridSelectedCellBorder");

    if (persist && cell && this._lastClicked) {
      var part1 = cell.getAttribute("pid");
      var clid1 = cell.getAttribute("clid");
      var ttid1 = cell.getAttribute("ttid");
      var cellid = (/^R(\d+)C(\d+)$/g).exec(cell.getAttribute("cid"));
      var row1 = Number(cellid[1]);
      var col1 = Number(cellid[2]);

      var part2 = this._lastClicked.getAttribute("pid");
      var clid2 = this._lastClicked.getAttribute("clid");
      var ttid2 = this._lastClicked.getAttribute("ttid");
      var cellid = (/^R(\d+)C(\d+)$/g).exec(this._lastClicked.getAttribute("cid"));
      var row2 = Number(cellid[1]);
      var col2 = Number(cellid[2]);

      if (part1 > part2) {
        var t = part2;
        part2 = part1;
        part1 = t;

        var t = clid2;
        clid2 = clid1;
        clid1 = t;

        var t = ttid2;
        ttid2 = ttid1;
        ttid1 = t;
      };

      if (col1 > col2) {
        var t = col2;
        col2 = col1;
        col1 = t;
      };

      if (row1 > row2) {
        var t = row2;
        row2 = row1;
        row1 = t;
      };

      var clone1 = this._parts[part1].table ? ((ttid1 == this._parts[part1].table.rn) ? this._parts[part1].table.clones.byKey[clid1] : this._parts[part1].table.totals.byKey[ttid1].clones.byKey[clid1]) : null;

      var clone2 = this._parts[part2].table ? ((ttid2 == this._parts[part2].table.rn) ? this._parts[part2].table.clones.byKey[clid2] : this._parts[part2].table.totals.byKey[ttid2].clones.byKey[clid2]) : null;

      if ((part1 == part2) && clone1 && clone2) {
        if (clone1.commonIndex > clone2.commonIndex) {
          var t = clone2;
          clone2 = clone1;
          clone1 = t;
        }
      }

      for (var i = col1; i <= col2; i++)
      for (var j = row1; j <= row2; j++) {
        var id = "R" + j + "C" + i;
        for (var p = part1; p <= part2; p++) {
          dojo.query("[cid=" + id + "]", this._parts[p].node).forEach(dojo.hitch(this, function(c) {

            if (c == cell) return;

            if ((p == part1) && clone1) {
              var ttid = c.getAttribute("ttid");
              var cloneIndex = (ttid == this._parts[part1].table.rn) ? this._parts[part1].table.clones.byKey[c.getAttribute("clid")].commonIndex : this._parts[part1].table.totals.byKey[ttid].clones.byKey[c.getAttribute("clid")].commonIndex;
              if (cloneIndex < clone1.commonIndex) return;
            };

            if ((p == part2) && clone2) {
              var ttid = c.getAttribute("ttid");
              var cloneIndex = (ttid == this._parts[part2].table.rn) ? this._parts[part2].table.clones.byKey[c.getAttribute("clid")].commonIndex : this._parts[part2].table.totals.byKey[ttid].clones.byKey[c.getAttribute("clid")].commonIndex;
              if (cloneIndex > clone2.commonIndex) return;
            }

            dojo.addClass(c, "templateGridSelectedCellBk");
            dojo.addClass(c, "templateGridSelectedCellBorder");
            dojo.query("[class]", c).addClass("templateGridSelectedCellBk");

          }));

        }
      }

      if (this._focusTemplateID) clearTimeout(this._focusTemplateID);
    }

    if (this._lastClicked) {
      dojo.removeClass(this._lastClicked, "templateGridActiveCellBorder");
      dojo.removeClass(this._lastClicked, "templateGridActiveCellBk");
      dojo.query("[class]", this._lastClicked).removeClass("templateGridActiveCellBk");
    };

    this._lastClicked = cell;
    dojo.addClass(this._lastClicked, "templateGridActiveCellBorder");
    dojo.addClass(this._lastClicked, "templateGridActiveCellBk");
    dojo.query("[class]", this._lastClicked).addClass("templateGridActiveCellBk");

    if (this._focusNodeConnection) dojo.disconnect(this._focusNodeConnection);
    this._lastClicked.appendChild(this.focusNode);
    this._focusNodeConnection = dojo.connect(this.focusNode, "onkeydown", this, this.keyDown);
  },

  _cellnums: 0,

  loadCells: function() {
    var cells = dojo.query("[cid]", this.templateNode);

    cells.forEach(dojo.hitch(this, function(cell) {
      this._cells[cell.getAttribute("cid")] = cell;
      cell.setAttribute("uid", this._cellnums++);
    }));

    cells.connect("onclick", dojo.hitch(this, function(e) {
      var evt = e || event;
      parus.parus8.registerAction();
      this.selectCell(evt, ( !! evt.shiftKey) || ( !! evt.altKey) || ( !! evt.ctrlKey));
      if (!evt.shiftKey && !evt.altKey && !evt.ctrlKey) this.focusTemplate();
    }));
  },

  loadStaticValues: function(response) {

    dojo.mixin(this._staticValues, {
      byKey: {}
    });

    var nodes = parus.parus8.rowNodes(response);


    dojo.forEach(nodes, dojo.hitch(this, function(index) {
      var id = "R" + parus.parus8.nodeField(index, "ROWN") + "C" + parus.parus8.nodeField(index, "COL");
      var dicts = parus.parus8.nodeField(index, "XMLDICTS");
      if (dicts) dicts = dojo.map(dicts, function(row) {
        return parus.parus8.nodeField(row, "DICT");
      });

      if (parus.parus8.nodeField(index, "CODE") && parus.parus8.extraDictionaries._canCacheExtraDictionaries) parus.parus8.extraDictionaries.getStore(parus.parus8.nodeField(index, "CODE"), this.agent, this.section);

      var staticValue = new parus.templateGridPaneInplaceEditor({
        id: id,
        pane: this,
        value: parus.parus8.externalStringToValue(parus.parus8.nodeField(index, "VALUE") || "", parus.parus8.nodeField(index, "BITYPE")),
        dataType: parus.parus8.nodeField(index, "BITYPE"),
        strLen: parus.parus8.nodeField(index, "STRLEN"),
        intPart: parus.parus8.nodeField(index, "INTPART"),
        fracPart: parus.parus8.nodeField(index, "FRACPART"),
        minVal: parus.parus8.nodeField(index, "MINVAL"),
        maxVal: parus.parus8.nodeField(index, "MAXVAL"),
        trim: parus.parus8.nodeField(index, "TRIMSTRVAL"),

        regExp: parus.parus8.nodeField(index, "PATTERN"),
        nullable: parus.parus8.nodeField(index, "NULLABLE") == "1",
        dictCheck: parus.parus8.nodeField(index, "DICT_CHECK") == "1",
        dictNote: parus.parus8.nodeField(index, "DICT_VAL_NOTE") == "1",

        col: parus.parus8.nodeField(index, "COL"),
        row: parus.parus8.nodeField(index, "ROWN"),
        dictionary: parus.parus8.nodeField(index, "CODE"),
        balanceIndex: parus.parus8.nodeField(index, "RN"),
        valueChanged: dojo.hitch(this, this.valueChanged),
        dicts: dojo.clone(dicts)
      });

      var node = this._cells[id];

      if (!node) return;

      this.__staticValuesIndex[node.getAttribute("uid")] = staticValue;

      node.setAttribute("iid", staticValue.balanceIndex);

      var canEdit = !(this.readonly) && !(node.getAttribute("ro")) && !(this.formulas[id]);

      if (canEdit) node.style.cursor = dojo.isIE ? "hand" : "pointer";

      dojo.mixin(staticValue, {
        node: node,
        canEdit: canEdit,
        valueNode: this.getValueNode(node),
        connection: canEdit ? dojo.connect(node, "onclick", dojo.hitch(staticValue, staticValue.clickHandler)) : null
      });

      if (staticValue.intPart) node.setAttribute("intpart", staticValue.intPart);
      if (staticValue.fracPart) node.setAttribute("fracpart", staticValue.fracPart);

      if ((staticValue.value !== "") && (staticValue.value !== null)) this.setCellText(node, staticValue.valueNode, staticValue.value);

      this._staticValues.push(staticValue);
      this._staticValues.byKey[staticValue.balanceIndex] = staticValue;

    }));

  },

  _expandTable: function(table) {
    if (table.gutterTreeNode) table.gutterTreeNode.attr("expanded", true);

    var cln = [];

    dojo.forEach(table.totals, function(total) {
      dojo.forEach(total.clones, function(clone) {
        if (clone.gutterTreeNode) cln.push(clone);
      })
    });

    cln.sort(function(a, b) {
      return (a.owner.level || 1000) - (b.owner.level || 1000);
    });
    dojo.forEach(cln, function(clone) {
      clone.gutterTreeNode.attr("expanded", true);
    });
  },

  _neighbor: function(cell, direction) {

    var cellid = (/^R(\d+)C(\d+)$/g).exec(cell.getAttribute("cid"));
    var rowid = Number(cellid[1]);
    var colid = Number(cellid[2]);

    if (this.direction == "1") {

      if (direction == "top") {
        while (rowid > 0) {
          rowid--;
          q = "[ids~=\"R" + rowid + "C" + colid + "\"]";
          var cells = dojo.query(q, cell.parentNode);
          if (cells.length) return cells[0];
        };

        return null;
      }
      else if (direction == "bottom") {
        rowid = rowid + parseInt(cell.getAttribute("rcnt"));
        while (rowid <= this.rows) {
          q = "[ids~=\"R" + rowid + "C" + colid + "\"]";
          var cells = dojo.query(q, cell.parentNode);
          if (cells.length) return cells[0];
          rowid++;
        }
        return null;
      }
      else if (direction == "left") {
        var pindex = cell.getAttribute("pid");
        var part = this._parts[pindex];
        var node = cell.parentNode;
        colid--;

        while (pindex >= 0) {

          var lb = part.col;

          while (node) {
            while (colid >= lb) {
              q = "[ids~=\"R" + rowid + "C" + colid + "\"]";
              var cells = dojo.query(q, node);
              if (cells.length) return cells[0];
              colid--;
            };

            node = part.table ? node.previousSibling : null;
            colid = part.col + part.width - 1;
          }

          pindex--;
          if (pindex >= 0) {
            part = this._parts[pindex];
            node = part.table ? part.node.lastChild : part.node;
            colid = part.col + part.width - 1;
          }
        }

        return null;

      }
      else if (direction == "right") {
        var pindex = cell.getAttribute("pid");
        var part = this._parts[pindex];
        var node = cell.parentNode;

        colid = colid + parseInt(cell.getAttribute("ccnt"));
        while (pindex < this._parts.length) {
          var ub = part.col + part.width - 1;
          while (node) {
            while (colid <= ub) {
              q = "[ids~=\"R" + rowid + "C" + colid + "\"]";
              var cells = dojo.query(q, node);
              if (cells.length) return cells[0];
              colid++;
            };

            node = part.table ? node.nextSibling : null;
            colid = part.col;
          }

          pindex++;
          if (pindex < this._parts.length) {
            part = this._parts[pindex];
            node = part.table ? part.node.firstChild : part.node;
            colid = part.col;
          }
        }

        return null;

      }
      else return null;



    }
    else {



      if (direction == "left") {
        while (colid > 0) {
          colid--;
          q = "[ids~=\"R" + rowid + "C" + colid + "\"]";
          var cells = dojo.query(q, cell.parentNode);
          if (cells.length) return cells[0];
        };

        return null;
      }
      else if (direction == "right") {
        colid = colid + parseInt(cell.getAttribute("ccnt"));
        while (colid <= this.cols) {
          q = "[ids~=\"R" + rowid + "C" + colid + "\"]";
          var cells = dojo.query(q, cell.parentNode);
          if (cells.length) return cells[0];
          colid++;
        }
        return null;
      }
      else if (direction == "top") {
        var pindex = cell.getAttribute("pid");
        var part = this._parts[pindex];
        var node = cell.parentNode;
        rowid--;

        while (pindex >= 0) {

          var lb = part.row;

          while (node) {
            while (rowid >= lb) {
              q = "[ids~=\"R" + rowid + "C" + colid + "\"]";
              var cells = dojo.query(q, node);
              if (cells.length) return cells[0];
              rowid--;
            };

            node = part.table ? node.previousSibling : null;
            rowid = part.row + part.height - 1;
          }

          pindex--;
          if (pindex >= 0) {
            part = this._parts[pindex];
            node = part.table ? part.node.lastChild : part.node;
            rowid = part.row + part.height - 1;
          }
        }

        return null;

      }

      else if (direction == "bottom") {
        var pindex = cell.getAttribute("pid");
        var part = this._parts[pindex];
        var node = cell.parentNode;
        rowid = rowid + parseInt(cell.getAttribute("rcnt"));
        while (pindex < this._parts.length) {
          var ub = part.row + part.height - 1;
          while (node) {
            while (rowid <= ub) {
              q = "[ids~=\"R" + rowid + "C" + colid + "\"]";
              var cells = dojo.query(q, node);
              if (cells.length) return cells[0];
              rowid++;
            };

            node = part.table ? node.nextSibling : null;
            rowid = part.row;
          }

          pindex++;
          if (pindex < this._parts.length) {
            part = this._parts[pindex];
            node = part.table ? part.node.firstChild : part.node;
            rowid = part.row;
          }
        }

        return null;

      }
      else return null;

    }

  },

  performConfirmation: function(action, canCancel) {
    if (this.modified) {
      (new parus.confirmationDialog({
        message: "Сохранить сделанные Вами изменения?",

        onShow: function() {
          if (canCancel) {
            this.cancelButton.domNode.style.display = "";
            this.noButton.onClick = dojo.hitch(this, function() {
              if (action) action();
              this.close();
            });
          }
        },

        onApply: dojo.hitch(this, function() {

          if (this.useHistory == "2")(new parus.confirmationDialog({
            message: "Сохранить историю значений?",
            onApply: dojo.hitch(this, function() {
              this.saveHistory(dojo.hitch(this, function() {
                this.saveValues(false, action)
              }));
              return true;
            }),
            onClose: dojo.hitch(this, function(dialog) {
              if (!dialog.applied) this.saveValues(false, action);
            })
          })).show();
          else if (this.useHistory == "1") {
            this.saveHistory(dojo.hitch(this, function() {
              this.saveValues(false, action)
            }));
          }
          else this.saveValues(false, action);
          return true;
        })
      })).show();

    }
    else action();
  },

  recalculate: function() {


    this.performConfirmation(

    dojo.hitch(this, function() {

      var dialog;

      var args = {
        noGrid: true,
        onClose: dojo.hitch(this, function() {

          if (dialog.applied) dojo.fadeOut({
            node: this.domNode,
            onEnd: dojo.hitch(this, function() {
              this.refreshTemplate();
            })
          }).play();

        })

      };

      if (this.subreport) {
        dojo.mixin(args, {
          rn: this.subreport,
          isSubReport: true
        });
      }
      else {

        dojo.mixin(args, {
          rn: this.report,
          isSubReport: false
        });

      };

      dialog = new parus.balanceReportRecalculateValuesDialog(args);
      dialog.show();

    }), true);

  },


  downloadExcel: function(extension, colormode) {

    this.performConfirmation(

    dojo.hitch(this, function() {
      setTimeout(dojo.hitch(this, function() {
        parus.balance.downloadExcelWorkBook(this.section ? "BalanceSubReports" : "BalanceReports", this.report, this.section ? this.subreport : null, this.template, extension, colormode);
      }), 100);
    }), true);

  },


  createPopupMenu: function() {

    var menu = new dijit.Menu({
      "class": "balanceMenu",

      preAction: dojo.hitch(this, function() {
        if (this.editing) if (this.editing.cancelValue) this.editing.cancelValue();
      }),

      _openMyself: dojo.hitch(this, function(args) {
        if (this.editing) if (this.editing.cancelValue) this.editing.cancelValue();
        var cell = args.target;
        while (cell && cell.getAttribute && (!cell.getAttribute("cid")))
        cell = cell.parentNode;
        if (cell && cell.getAttribute) {
          this.selectCell(cell);
          dijit.Menu.prototype._openMyself.apply(menu, arguments);
        }
      })

    });

    menu.addChild(new dijit.MenuItem({
      label: "Сохранить значения",
      defaultIcon: "PCfloppyCustomIcon",
      disabled: this.readonly,
      onClick: dojo.hitch(this, function() {
        var action = dojo.hitch(this, function() {
          parus.parus8.notificationMessage("Значения успешно сохранены.")
        });

        if (this.useHistory == "2")

        (new parus.confirmationDialog({
          message: "Сохранить историю значений?",
          onApply: dojo.hitch(this, function() {
            this.saveHistory(dojo.hitch(this, function() {
              this.saveValues(false, action)
            }));
            return true;

          }),
          onClose: dojo.hitch(this, function(dialog) {
            if (!dialog.applied) this.saveValues(false, action);
          })

        })).show();

        else if (this.useHistory == "1") {
          this.saveHistory(dojo.hitch(this, function() {
            this.saveValues(false, action)
          }));
        }

        else this.saveValues(false, action)


      })
    }));


    if (this.useHistory == "1") menu.addChild(new dijit.MenuItem({
      label: "Сохранить историю значений",
      disabled: this.readonly,
      onClick: dojo.hitch(this, function() {
        this.saveHistory(dojo.hitch(this, function() {
          parus.parus8.notificationMessage("История значений успешно сохранена.");
        }));
      })
    }));

    if (this.kind == 0) {

      menu.addChild(new dijit.MenuSeparator());
      menu.addChild(new dijit.MenuItem({
        label: "Пересчитать...",
        defaultIcon: "PCcalculator2CustomIcon",
        disabled: this.readonly,
        onClick: dojo.hitch(this, this.recalculate)
      }));
    }

    menu.addChild(new dijit.MenuSeparator());
    menu.addChild(new dijit.MenuItem({
      label: "Проверить...",
      defaultIcon: "PCCheckCustomIcon",
      onClick: dojo.hitch(this, this.checkValues)
    }));
    menu.addChild(new dijit.MenuItem({
      label: "Протокол проверки...",
      onClick: dojo.hitch(this, this.checkReport)
    }));


    menu.addChild(new dijit.MenuSeparator());

    var remarksMenu = new dijit.Menu({
      "class": "balanceMenu"
    });

    remarksMenu.addChild(new dijit.MenuItem({
      label: "Добавить...",
      disabled: this.readonly,
      onClick: dojo.hitch(this, function() {


        if (!this._lastClicked) return;

        var indexID = this._lastClicked.getAttribute("iid");
        var tid = this._lastClicked.getAttribute("tid");
        var clid = this._lastClicked.getAttribute("clid");

        if (!indexID) {
          parus.parus8.errorMessage("Укажите показатель, к которому вы хотите <br/>добавить замечение.");
          return;
        };

        var query = {
          INDEXRN: indexID
        };

        if (tid) dojo.mixin(query, {
          CLONERN: clid,
          TABLERN: tid
        });

        this.createRemark(query);

      })
    }));


    remarksMenu.addChild(new dijit.MenuItem({
      label: "Просмотреть...",
      onClick: dojo.hitch(this, this.indexRemarks)
    }));

    remarksMenu.addChild(new dijit.MenuItem({
      label: "Отобразить",
      onClick: dojo.hitch(this, this.showRemarksPopups)
    }));
    remarksMenu.addChild(new dijit.MenuItem({
      label: "Скрыть",
      onClick: dojo.hitch(this, this.hideRemarksPopups)
    }));

    menu.addChild(new dijit.PopupMenuItem({
      label: "Замечания",
      popup: remarksMenu
    }));


    menu.addChild(new dijit.MenuSeparator());

    var tableMenu = new dijit.Menu({
      "class": "balanceMenu"
    });

    if (this.direction == "0") {

      tableMenu.addChild(new dijit.MenuItem({
        label: "Добавить строку",
        defaultIcon: "PCHardwareadaltCustomIcon",
        disabled: this.readonly,
        onClick: dojo.hitch(this, this.addClone)
      }));
      tableMenu.addChild(new dijit.MenuItem({
        label: "Размножить строку",
        defaultIcon: "PCcopyCustomIcon",
        disabled: this.readonly,
        onClick: dojo.hitch(this, this.duplicateClone)
      }));
      tableMenu.addChild(new dijit.MenuItem({
        label: "Удалить строку",
        defaultIcon: "PCreduceCustomIcon",
        disabled: this.readonly,
        onClick: dojo.hitch(this, this.deleteClone)
      }));

      tableMenu.addChild(new dijit.MenuSeparator());

      tableMenu.addChild(new dijit.MenuItem({
        label: "Добавить группу строк...",
        disabled: this.readonly,
        onClick: dojo.hitch(this, this.addClones)
      }));

      tableMenu.addChild(new dijit.MenuItem({
        label: "Удалить группу строк...",
        disabled: this.readonly,
        onClick: dojo.hitch(this, this.deleteClones)
      }));

    }
    else {

      tableMenu.addChild(new dijit.MenuItem({
        label: "Добавить столбец",
        defaultIcon: "PCHardwareadaltCustomIcon",
        disabled: this.readonly,
        onClick: dojo.hitch(this, this.addClone)
      }));
      tableMenu.addChild(new dijit.MenuItem({
        label: "Размножить столбец",
        defaultIcon: "PCcopyCustomIcon",
        disabled: this.readonly,
        onClick: dojo.hitch(this, this.duplicateClone)
      }));
      tableMenu.addChild(new dijit.MenuItem({
        label: "Удалить столбец",
        defaultIcon: "PCreduceCustomIcon",
        disabled: this.readonly,
        onClick: dojo.hitch(this, this.deleteClone)
      }));
      tableMenu.addChild(new dijit.MenuItem({
        label: "Добавить группу столбцов...",
        disabled: this.readonly,
        onClick: dojo.hitch(this, this.addClones)
      }));

    }

    menu.addChild(new dijit.PopupMenuItem({
      label: "Таблица",
      popup: tableMenu
    }));

    menu.addChild(new dijit.MenuSeparator());
    menu.addChild(new dijit.MenuItem({
      label: "Состав показателя...",
      defaultIcon: "PCsherlockCustomIcon",
      onClick: dojo.hitch(this, this.indexCons)
    }));

    menu.addChild(new dijit.MenuItem({
      label: "Добавить к сравнению...",
      defaultIcon: "PCDefaultappsCustomIcon",
      onClick: dojo.hitch(this, this.addToConsComparation)
    }));

    menu.addChild(new dijit.MenuItem({
      label: "Сравнить по шаблону...",
      onClick: dojo.hitch(this, this.addTemplateToConsComparation)
    }));

    this._checkConsComparationMenuItem = new dijit.MenuItem({
      label: "Сравнить состав показателей...",
      defaultIcon: "PCwifiCustomIcon",
      onClick: dojo.hitch(this, this.consComparation)
    });

    menu.addChild(this._checkConsComparationMenuItem);

    menu.addChild(new dijit.MenuItem({
      label: "Очистить параметры сравнения...",
      onClick: dojo.hitch(this, this.clearConsComparation)
    }));


    menu.addChild(new dijit.MenuSeparator());

    menu.addChild(new dijit.MenuItem({
      label: "Выгрузить в Excel...",
      defaultIcon: "PCxlsCustomIcon",
      onClick: dojo.hitch(this, this.downloadExcel, "xls", 0)
    }));
    menu.addChild(new dijit.MenuItem({
      label: "Выгрузить в формате PDF...",
      onClick: dojo.hitch(this, this.downloadExcel, "pdf", null)
    }));
    menu.addChild(new dijit.MenuItem({
      label: "Выгрузить в формате HTML...",
      onClick: dojo.hitch(this, this.downloadExcel, "html", null)
    }));

    menu.addChild(new dijit.MenuSeparator());
    menu.addChild(new dijit.MenuItem({
      label: "Обновить",
      defaultIcon: "PCisyncCustomIcon",
      onClick: dojo.hitch(this, this.reload)
    }));
    menu.addChild(new dijit.MenuItem({
      label: "Выбрать трафарет...",
      onClick: dojo.hitch(this, this.chooseTemplate)
    }));


    var zoomMenu = new dijit.Menu({
      "class": "balanceMenu"
    });

    zoomMenu.addChild(new dijit.MenuItem({
      label: "Увеличить",
      onClick: dojo.hitch(this, function() {
        this.changeZoom(1);
      })
    }));

    zoomMenu.addChild(new dijit.MenuItem({
      label: "Уменьшить",
      onClick: dojo.hitch(this, function() {
        this.changeZoom(-1);
      })
    }));

    zoomMenu.addChild(new dijit.MenuSeparator());


    zoomMenu.addChild(new dijit.MenuItem({
      label: "100%",
      onClick: dojo.hitch(this, function() {
        this.changeZoom(0);
      })
    }));

    if (this.defaultZoom != 100) zoomMenu.addChild(new dijit.MenuItem({
      label: "По умолчанию (" + this.defaultZoom + "%)",
      onClick: dojo.hitch(this, function() {
        this.zoom = this.defaultZoom / 100;
        this._zoomChanged();
      })
    }));

    zoomMenu.addChild(new dijit.MenuItem({
      label: "Задать...",
      onClick: dojo.hitch(this, function() {

        var dialog = new parus.balanceZoomDialog({
          onShow: dojo.hitch(this, function() {
            dialog.zoomEdit.attr("value", this.zoom * 100);
          }),

          onApply: dojo.hitch(this, function() {

            this.zoom = dialog.zoomEdit.attr("value") / 100;
            this._zoomChanged();

            return true;

          })

        });

        dialog.show();

      })
    }));


    menu.addChild(new dijit.MenuSeparator());
    menu.addChild(new dijit.PopupMenuItem({
      label: "Масштаб",
      popup: zoomMenu
    }));


    menu.addChild(new dijit.MenuSeparator());
    menu.addChild(new dijit.MenuItem({
      //      disabled: this.readonly,
      label: "Скопировать значения в буфер",
      onClick: dojo.hitch(this, function() {
        this.copySelection();
      })
    }));
    menu.addChild(new dijit.MenuItem({
      label: "Вставить значения из буфера",
      disabled: this.readonly,
      onClick: dojo.hitch(this, function() {

        if (!parus.parus8._internalClipboard) {
          parus.parus8.errorMessage("Скопируйте в буфер какие-нибудь ячейки.<br/>" + "Для этого щелкните по противоположному углу выделяемой области, придерживая клавишу Ctrl,<br/>" + "и выполните действие <br/>\"Скопировать значения в буфер\"");
          return;
        };

        if (!this._lastClicked) {
          parus.parus8.errorMessage("Укажите ячейку, в которую вы хотите вставить содержимое буфера.");
          return;
        };

        this._doPasteTexts(this._lastClicked, parus.parus8._internalClipboard);

      })
    }));

    menu.addChild(new dijit.MenuSeparator());
    menu.addChild(new dijit.MenuItem({
      label: "Настройки...",
      onClick: dojo.hitch(this, function() {
        parus.balance.executeSettings(null, menu, this.declaredClass + this.kind, null, [{
          title: "Отображать иерархию итогов при открытии отчета",
          id: "showGutter",
          get: function() {
            return parus.balance.showTemplateGutter;
          },
          set: function(value) {
            parus.balance.showTemplateGutter = value;
            var settings = parus.userdata.get("parus.balance.primaryMasterGrid");
            settings.additions.showGutter = parus.balance.showTemplateGutter;
            parus.userdata.set("parus.balance.primaryMasterGrid", settings)
          }
        }]);
      })
    }));

    menu.startup();
    return menu;
  },

  copySelection: function() {

    var dims = [];

    dojo.query(".templateGridSelectedCellBorder,.templateGridActiveCellBorder", this.templateNode).forEach(dojo.hitch(this, function(node) {
      var clid = node.getAttribute("clid");
      var cellid = (/^R(\d+)C(\d+)$/g).exec(node.getAttribute("cid"));
      var row = Number(cellid[1]);
      var col = Number(cellid[2]);

      if (!dims[clid || 0]) dims[clid || 0] = [];

      if (!dims[clid || 0][row]) dims[clid || 0][row] = [];

      dims[clid || 0][row][col] = parus.parus8.getTextContent(this.getValueNode(node) || node);
    }));

    var rows = [];

    dojo.forEach(dims, function(d1) {
      if (d1) dojo.forEach(d1, function(d2) {
        if (d2) {
          var row = [];
          dojo.forEach(d2, function(d3) {
            if (d3 != undefined) row.push(d3);
          });
          if (row.length) rows.push(row);
        }
      });
    });

    if (rows.length) parus.parus8._internalClipboard = rows;
    else parus.parus8._internalClipboard = null;

    var text = dojo.map(rows, function(row) {
      return dojo.map(row, function(cell) {
        return cell;
      }).join("\t");
    }).join("\n");

    this.clipboardNode.value = text;

    this.clipboardNode.select();
    dijit.focus(this.clipboardNode);

    try {
      document.execCommand('copy');
    } catch (err) {};

    dijit.focus(this.focusNode);

  },

  _doPasteTexts: function(cell, text) {

    var pane = this;

    var node = cell;
    var lineNode = node;
    var modified = false;

    dojo.forEach(text, function(line) {

      if (lineNode) {

        var colNode = lineNode;

        dojo.forEach(line, function(row) {
          if (colNode) {

            var staticValue = pane.__staticValuesIndex[colNode.getAttribute("uid")];

            if (staticValue) if (staticValue.canEdit) {

              row = dojo.trim(row);
              pane.setCellText(staticValue.node, staticValue.valueNode, parus.parus8.externalStringToValue(row, staticValue.dataType));
              staticValue.modified = true;
              staticValue.valueChanged(staticValue.id);
              modified = true;
            };

            colNode = pane._neighbor(colNode, "right");

          }

        });

        lineNode = pane._neighbor(lineNode, "bottom");
      }
    });

    if (modified) {
      pane.modified = true;
      pane.onModified();
    }

  },

  indexRemarks: function() {

    if (!this._lastClicked) return;

    var indexID = this._lastClicked.getAttribute("iid");
    var tid = this._lastClicked.getAttribute("tid");
    var clid = this._lastClicked.getAttribute("clid");

    if (!indexID) {
      parus.parus8.errorMessage("Укажите показатель, замечания к которому <br/>вы хотите посмотреть.");
      return;
    };

    var query = {
      INDEXRN: indexID
    };

    if (tid) dojo.mixin(query, {
      CLONERN: clid,
      TABLERN: tid
    });

    var dialog = new parus.balanceRemarksDialog({
      pane: this,
      store: this._remarksStore,
      queryInfo: query,
      readonly: this.readonly

    });
    dialog.show();

  },

  hideRemarksPopups: function() {
    dojo.query("[rid='h']", this.templateNode).orphan();
    this.remarksShown = false;
  },

  showRemarksPopups: function() {
    this.hideRemarksPopups();

    var marks = {};

    if (this._gutterLevels) dojo.forEach(this._gutterLevels, function(level) {
      level._expand();
    });

    this._remarksStore.forEach(dojo.hitch(this, function(store, params) {

      var key = store.getValue(params, "INDEXRN");
      if (store.getValue(params, "CLONERN")) key = key + ";" + store.getValue(params, "CLONERN");
      if (store.getValue(params, "TABLERN")) key = key + ";" + store.getValue(params, "TABLERN");

      var cell = null;
      if (store.getValue(params, "TABLERN")) {
        var table = this._tables.byKey[store.getValue(params, "TABLERN")];
        if (!table) return;
        var clone = table.clones.byKey[store.getValue(params, "CLONERN")];
        if (!clone) return;
        var value = clone._staticValues.byKey[store.getValue(params, "INDEXRN")];
        if (value) cell = value.node;

      }
      else {
        var value = this._staticValues.byKey[store.getValue(params, "INDEXRN")];
        if (value) cell = value.node;
      };
      if (!cell) return;


      marks[key] = {
        cell: cell,
        params: params
      };

    }), true);


    var tc = dojo.coords(this.templateNode);

    for (var key in marks) {
      var cell = marks[key].cell;
      var params = marks[key].params;

      var n = cell;
      var cc = dojo.coords(n);
      while (n.getAttribute("rid") != "w") {
        n = n.parentNode;
        var ccc = dojo.coords(n);
        cc.t += ccc.t;
        cc.l += ccc.l;
      };

      var node = dojo.place(

      "<div rid=\"h\" hid=\"" + key + "\" style=\"z-index:50;cursor: pointer;\" onclick=\"parus.templateGridPane.remarkToTop(this)\" class=\"dijitPopup dijitTooltipDialogPopup\">" + "<div class=\"dijitTooltipDialog dijitTooltipBelow dijitTooltipABRight\">" + "<div class=\"dijitTooltipContainer templateHintContainer\">" + "<div style=\"font-size: 80%;font-weight: 600;border-bottom: 1px solid black;\">" +

      this._remarksStore.getValue(params, "NAME") + " " + this._remarksStore.getValue(params, "CHANGE_DATE") + "</div>" + "<div style=\"margin-top:5px;font-weight:700;\">" + this._remarksStore.getValue(params, "NOTE") + "</div>" + "</div>" + "<div class=\"dijitTooltipConnector templateHintConnector\"></div>" + "</div>" + "</div>", this.templateNode, "last");

      var nc = dojo.coords(node);

      dojo.style(node, {
        position: "absolute",
        left: (cc.l - tc.l + cc.w - nc.w) + "px",
        top: (cc.t - tc.t + cc.h) + "px"
      });

    }

    this.remarksShown = true;

  },

  clearRemarks: function(params, onMainApply) {

    var response = parus.database.execute("ClearRemarksAccess", {
      SUBREPORT: this.subreport || "0",
      REPORT: this.report || "0",
      TABLERN: params["TABLERN"] || "0"
    });

    if (response) {

      var key = params["INDEXRN"];
      if (params["CLONERN"]) key = key + ";" + params["CLONERN"];
      if (params["TABLERN"]) key = key + ";" + params["TABLERN"];
      this._remarksStore.remove(function(item) {
        var akey = parus.parus8.nodeField(item, "INDEXRN");
        if (parus.parus8.nodeField(item, "CLONERN")) akey = akey + ";" + parus.parus8.nodeField(item, "CLONERN");
        if (parus.parus8.nodeField(item, "TABLERN")) akey = akey + ";" + parus.parus8.nodeField(item, "TABLERN");
        return (akey == key);
      });

      var obj = {
        "INDEXRN": params["INDEXRN"]
      };
      if (params["CLONERN"]) dojo.mixin(obj, {
        "CLONERN": params["CLONERN"]
      });
      if (params["TABLERN"]) dojo.mixin(obj, {
        "TABLERN": params["TABLERN"]
      });

      dojo.query("[hid=" + key + "]", this.templateNode).orphan();

      this.applyRemarkColor(obj);

      if (onMainApply) onMainApply();

      this.modified = true;
      this.onModified();
    }
  },

  createRemark: function(params, onMainApply) {

    var response = parus.database.execute("AddRemarkAccess", {
      SUBREPORT: this.subreport || "0",
      REPORT: this.report || "0",
      TABLERN: params["TABLERN"] || "0"
    });

    if (response) {


      var dialog = new parus.balanceRemarkDialog({
        onShow: dojo.hitch(this, function() {
          dialog.noteEdit.attr("value", "");
          if (params["NOTE"]) dialog.noteEdit.attr("value", params["NOTE"]);
          if (params["CODE"]) dialog.statusEdit.attr("value", params["CODE"]);
        }),

        onApply: dojo.hitch(this, function() {

          var remarkInfo = parus.parus8.rowNodes(parus.database.execute("BalanceRemarkInfo", {
            "CODE": dialog.statusEdit.attr("value"),
            "REPORT": this.report
          }))[0];

          var maxNumb = 0;
          var key = params["INDEXRN"];
          if (params["CLONERN"]) key = key + ";" + params["CLONERN"];
          if (params["TABLERN"]) key = key + ";" + params["TABLERN"];

          dojo.forEach(this._remarksStore._data, function(item) {
            var akey = parus.parus8.nodeField(item, "INDEXRN");

            if (parus.parus8.nodeField(item, "CLONERN")) akey = akey + ";" + parus.parus8.nodeField(item, "CLONERN");
            if (parus.parus8.nodeField(item, "TABLERN")) akey = akey + ";" + parus.parus8.nodeField(item, "TABLERN");
            if (key == akey) {
              var i = parseInt(parus.parus8.nodeField(item, "NUMB"));
              if (i > maxNumb) maxNumb = i;
            }
          });

          dojo.mixin(params, {
            NUMB: ++maxNumb,
            CHANGE_DATE: parus.parus8.nodeField(remarkInfo, "CHANGE_DATE"),
            NAME: parus.parus8.nodeField(remarkInfo, "NAME"),
            COLOR: parus.parus8.nodeField(remarkInfo, "COLOR"),
            NOTE: dialog.noteEdit.attr("value"),
            CODE: dialog.statusEdit.attr("value"),
            _NEW: true
          });

          this._remarksStore.add(params);

          this.applyRemarkColor(params);

          if (this.remarksShown) this.showRemarksPopups();

          if (onMainApply) onMainApply();

          this.modified = true;
          this.onModified();

          return true;
        })


      });

      dialog.show();
    }

  },

  applyRemarkColor: function(params) {
    var cell = null;
    if (parus.parus8.nodeField(params, "TABLERN")) {
      var table = this._tables.byKey[parus.parus8.nodeField(params, "TABLERN")];
      if (!table) return;
      var clone = table.clones.byKey[parus.parus8.nodeField(params, "CLONERN")];
      if (!clone) return;
      var value = clone._staticValues.byKey[parus.parus8.nodeField(params, "INDEXRN")];
      if (value) cell = value.node;
    }
    else {
      var value = this._staticValues.byKey[parus.parus8.nodeField(params, "INDEXRN")];
      if (value) cell = value.node;
    };
    if (!cell) return;

    if (parus.parus8.nodeField(params, "COLOR")) {
      if (dojo.isIE == "8") {
        if (!cell.getAttribute("no-remark-color")) cell.setAttribute("no-remark-color", cell.style.backgroundColor || "inherit");
      }
      else {
        if (!cell.hasAttribute("no-remark-color")) cell.setAttribute("no-remark-color", cell.style.backgroundColor);
      }
      cell.style.backgroundColor = parus.parus8.colorToCssColor(parus.parus8.nodeField(params, "COLOR"));
    }
    else cell.style.backgroundColor = cell.getAttribute("no-remark-color");
  },

  consComparation: function() {
    if (!parus.parus8.consComparationData) {
      parus.parus8.errorMessage("Необходимо сначала добавить показатели, состав которых вы хотите сравнить.");
      return;
    };

    parus.parus8.showIndexConsComparationItems({
      onClose: dojo.hitch(this, this._checkConsComparationIcon)
    });
  },

  addTemplateToConsComparation: function() {


    var dialog = new parus.balanceIndexConsComparationTemplatesDialog({

      onApply: dojo.hitch(this, function() {
        dojo.forEach(dialog.templatesGrid.selection.getSelected(), function(item) {
          parus.parus8.addIndexConsComparationTemplate(item);
        });
        parus.parus8.consComparationDataModified();
        this._checkConsComparationIcon();
        if (parus.parus8.consComparationData) parus.parus8.showIndexConsComparationItems({
          onClose: dojo.hitch(this, this._checkConsComparationIcon)
        });
        return true;
      })

    });
    dialog.show();
  },

  addToConsComparation: function() {

    if (!this._lastClicked) return;

    var indexID = this._lastClicked.getAttribute("iid");
    var tid = this._lastClicked.getAttribute("tid");
    var clid = this._lastClicked.getAttribute("clid");

    if (!indexID) {
      parus.parus8.errorMessage("Укажите показатель, состав которого <br/>вы хотите добавить к сравнению.");
      return;
    };

    var info = parus.parus8.rowNodes(parus.database.execute("IndexConsInfo", {
      "REPORT": this.report,
      "SUBREPORT": this.subreport,
      "INDEX": indexID,
      "TABLE": tid,
      "ROWID": clid
    }))[0];

    parus.parus8.consComparationData = parus.parus8.consComparationData || {
      dataType: parus.parus8.nodeField(info, "DATATYPE"),
      result: parus.parus8.nodeField(info, "RESULT"),
      intPart: parus.parus8.nodeField(info, "INTPART"),
      fracPart: parus.parus8.nodeField(info, "FRACPART"),
      items: []
    };

    parus.parus8.consComparationData.intPart =
    Math.max(parus.parus8.consComparationData.intPart || 0, parus.parus8.nodeField(info, "INTPART") || 0);

    parus.parus8.consComparationData.fracPart =
    Math.max(parus.parus8.consComparationData.fracPart || 0, parus.parus8.nodeField(info, "FRACPART") || 0);

    if (parus.parus8.consComparationData.dataType != parus.parus8.nodeField(info, "DATATYPE")) {
      parus.parus8.errorMessage("Тип показателя не соответствует уже добавленным к сравнению показателям.");
      return;
    };

    if (parus.parus8.consComparationData.result != parus.parus8.nodeField(info, "RESULT")) {
      parus.parus8.errorMessage("Тип состава показателя не соответствует уже добавленным к сравнению показателям.");
      return;
    };

    parus.parus8.addIndexConsComparationItem({
      "REPORT": this.report,
      "SUBREPORT": this.subreport,
      "INDEX": indexID,
      "TABLE": tid,
      "ROWID": clid,
      "TITLE": parus.parus8.nodeField(info, "TITLE")
    });

    this._checkConsComparationIcon();

    //parus.parus8.showIndexConsComparationItems();
  },

  clearConsComparation: function() {

    (new parus.confirmationDialog({

      message: "Очистить список показателей для сравнения состава?",

      onApply: dojo.hitch(this, function() {
        parus.parus8.consComparationData = null;
        parus.parus8.consComparationDataModified();
        this._checkConsComparationIcon();
        return true;
      })
    })).show();


  },

  indexCons: function() {

    if (!this._lastClicked) return;

    var indexID = this._lastClicked.getAttribute("iid");
    var tid = this._lastClicked.getAttribute("tid");
    var clid = this._lastClicked.getAttribute("clid");

    if (!indexID) {
      parus.parus8.errorMessage("Укажите показатель, состав которого <br/>вы хотите посмотреть.");
      return;
    };

    var queryConditions = {
      "REPORT": this.report,
      "SUBREPORT": this.subreport,
      "INDEX": indexID,
      "TABLE": tid,
      "ROWID": clid
    };

    var idData = parus.parus8.nodeField(parus.parus8.rowNodes(parus.database.execute("IndexConsIDData", {
      "REPORT": this.report,
      "SUBREPORT": this.subreport,
      "INDEX": indexID,
      "TABLE": tid,
      "ROWID": clid
    }))[0], "clobDATA");

    parus.database.execute("IndexCons", queryConditions, dojo.hitch(this, function(response) {

      var consItems =
      response.documentElement.childNodes[0].childNodes[0].childNodes.length ? parus.parus8.rowNodes(response.documentElement.childNodes[0].childNodes[0].childNodes[0]) : [];
      if (consItems.length == 0) {
        parus.parus8.errorMessage("Показатель не имеет состава.");
        return;
      };

      var dialog = new parus.balanceIndexConsDialog({

        intPart: response.documentElement.childNodes[0].childNodes[2].firstChild.childNodes[0].firstChild ? response.documentElement.childNodes[0].childNodes[2].firstChild.childNodes[0].firstChild.nodeValue : null,

        fracPart: response.documentElement.childNodes[0].childNodes[2].firstChild.childNodes[1].firstChild ? response.documentElement.childNodes[0].childNodes[2].firstChild.childNodes[1].firstChild.nodeValue : null,

        consItems: consItems,

        queryConditions: queryConditions,

        description: response.documentElement.childNodes[0].childNodes[1].firstChild.nodeValue,

        onApply: dojo.hitch(this, function() {


          dojo.forEach(dialog.consItemsGrid.selection.getSelected(), dojo.hitch(this, function(item) {

            var report = dialog.consItemsGrid.store.getValue(item, "REPORT", "");
            var subreport = dialog.consItemsGrid.store.getValue(item, "SUBREPORT", "");

            if (this.autonomousMode && !parus.parus8._embeddedMode) {

              if (parus.parus8._themeEditorMode) {
                alert("В режиме редактирования схемы это действие невозможно.");
                return;
              }

              window.open(dojo.moduleUrl("parus", "report.html") + "?loggedUserHandler=" + parus.database.connected + "&params=" + parus.parus8.hexEncodeParams([report, subreport, this.template]), "_blank");
            }
            else if (parus.parus8._embeddedMode) {

              var url = dojo.moduleUrl("parus", "report.html") + "?loggedUserHandler=" + parus.database.connected + "&params=" + parus.parus8.hexEncodeParams([report, subreport, this.template]);
              var title = parus.balance.describeReport(report, subreport, this.template, null, null, null, null, 0);
              var id = [report, subreport, (+(new Date))].join("_");
              parus.embeddedMode.openTab(null, title, url);

            }
            else {


              var idDataQuery = idData;

              idDataQuery = idDataQuery.replace(/(<AGENT>)(.*)(<\/AGENT>)/, "$1" + (dialog.consItemsGrid.store.getValue(item, "AGNABBR", "") || "") + "$3");
              idDataQuery = idDataQuery.replace(/(<KIND>)(.*)(<\/KIND>)/, "$1" + (dialog.consItemsGrid.store.getValue(item, "KIND", "") || "") + "$3");
              idDataQuery = idDataQuery.replace(/(<SECTION>)(.*)(<\/SECTION>)/, "$1" + (dialog.consItemsGrid.store.getValue(item, "CODE", "") || "") + "$3");

              parus.balance.showReportValues(
              report, subreport, this.reportDate, this.formCode, dialog.consItemsGrid.store.getValue(item, "AGNABBR", ""), dialog.consItemsGrid.store.getValue(item, "CODE", ""), this.template, this.direction, dialog.consItemsGrid.store.getValue(item, "KIND", ""), dialog.consItemsGrid.store.getValue(item, "AGENT", ""),

              function(pane) {
                var id = parus.parus8.rowNodes(parus.database.execute("IndexConsDataID", {
                  "DATA": idDataQuery
                }))[0];
                parus.templateGridPane.followLogMessage(pane.id, parus.parus8.nodeField(id, "INDEX"), parus.parus8.nodeField(id, "TABLE"), parus.parus8.nodeField(id, "ROWID"), parus.parus8.nodeField(id, "INDEX"));
              });

            }


          }));



          return true;
        })


      });
      dialog.show();


    }));

  },

  deleteClone: function() {
    if (!this._lastClicked) return;

    if (!this._lastClicked.getAttribute("tid")) {
      parus.parus8.errorMessage("Укажите таблицу, из которой<br/>необходимо удалить строку или столбец.");
      return;
    }

    var table = this._tables.byKey[this._lastClicked.getAttribute("tid")];

    if (!table) {
      parus.parus8.errorMessage("Укажите таблицу, из которой<br/>необходимо удалить строку или столбец.");
      return;
    }

    if (table.readOnly) {
      parus.parus8.errorMessage("Удаление строк или столбцов таблицы невозможно, т.к. таблица защищена от изменений");
      return;
    }

    if (!this._lastClicked.getAttribute("clid")) {
      parus.parus8.errorMessage("Укажите таблицу, из которой<br/>необходимо удалить строку или столбец.");
      return;
    }

    var clone = table.clones.byKey[this._lastClicked.getAttribute("clid")];

    if (!clone) {
      parus.parus8.errorMessage("Эту строку или столбец удалить нельзя.");
      return;
    }

    this._expandTable(table);

    clone.node.parentNode.removeChild(clone.node);

    if (clone.size) {
      this.shiftClones(table, clone.commonIndex, -clone.size)
      this.shiftParts(clone.table.part, -clone.size);
    }

    clone.table.offsetSize = clone.table.offsetSize - clone.size;

    clone.owner.clones.splice(dojo.indexOf(clone.owner.clones, clone), 1);
    delete clone.owner.clones.byKey[clone.rn];

    if (!table.clones.length) {
      table.placeClone(null, true);
    };

    this.valueChanged();

    this.modified = true;
    this.onModified();

  },

  __deferredAttrs: null,

  __fireDefferedAttrs: function() {

    if (!this.__deferredAttrs) return;

    for (var key in this.__deferredAttrs) {
      var diff = this.__deferredAttrs[key];
      if (diff.h || diff.w) {
        var style = {};
        if (diff.h) style["height"] = (diff.h) + "px";
        if (diff.w) style["width"] = (diff.w) + "px";
        dojo.style(diff.cell, style);
      }
    }

    for (var key in this.__deferredAttrs) {
      var diff = this.__deferredAttrs[key];
      if (diff.dx || diff.dy || diff.dh || diff.dw) {
        var style = {};
        if (diff.dx) style["left"] = (parus.parus8.styleSize(diff.cell.style.left) + diff.dx) + "px";
        if (diff.dy) style["top"] = (parus.parus8.styleSize(diff.cell.style.top) + diff.dy) + "px";
        if (diff.dh) {
          var v = parus.parus8.styleSize(diff.cell.style.height);
          if (!v) v = dojo.marginBox(diff.cell).h;
          style["height"] = (v + diff.dh) + "px";
        }
        if (diff.dw) {
          var v = parus.parus8.styleSize(diff.cell.style.width);
          if (!v) v = dojo.marginBox(diff.cell).w;
          style["width"] = (v + diff.dw) + "px";
        }
        dojo.style(diff.cell, style);
      }
    }

    this.__deferredAttrs = null;

  },

  __setDefferedAttr: function(cell, attr, difference) {
    if (!this.__deferredAttrs) this.__deferredAttrs = {};

    var uid = cell.getAttribute("uid");

    var diffs = this.__deferredAttrs[uid] || {
      dx: 0,
      dy: 0,
      dh: 0,
      dw: 0,
      h: 0,
      w: 0,
      cell: cell
    };
    if ((attr == "w") || (attr == "h")) diffs[attr] = difference;
    else diffs[attr] += difference;
    this.__deferredAttrs[uid] = diffs;
  },

  shiftClones: function(table, cloneIndex, size, deferred) {
    if (!size) return;

    var func = dojo.hitch(this, deferred ? (

    (this.direction == "0") ?
    function(cell) {
      this.__setDefferedAttr(cell, "dy", size)
    } : function(cell) {
      this.__setDefferedAttr(cell, "dx", size)
    }

    ) : ((this.direction == "0") ?
    function(cell) {
      dojo.style(cell, {
        top: (parus.parus8.styleSize(cell.style.top) + size) + "px"
      });
    } : function(cell) {
      dojo.style(cell, {
        left: (parus.parus8.styleSize(cell.style.left) + size) + "px"
      });
    }));

    var thisclone;


    dojo.forEach(table.clones, function(clone) {
      if (clone.commonIndex == cloneIndex) thisclone = clone
      else if (clone.commonIndex > cloneIndex) {
        func(clone.node);
      }
    });

    if (!thisclone) dojo.forEach(table.totals, function(total) {
      dojo.forEach(total.clones, function(clone) {
        if (clone.commonIndex == cloneIndex) thisclone = clone
      })
    });

    dojo.forEach(table.totals, function(total) {
      dojo.forEach(total.clones, function(clone) {
        if (clone.commonIndex > cloneIndex) {
          func(clone.node);
          if (clone.gutterTreeNode) {

            if (dojo.indexOf(clone.treeChildren || [], thisclone) >= 0) {
              clone.gutterTreeNode.height += size;
            }
            else {
              clone.gutterTreeNode.top += size;
            }

            clone.gutterTreeNode._resize();
          }
        }
        else if (clone.gutterTreeNode && (dojo.indexOf(clone.treeChildren || [], thisclone) >= 0)) {
          clone.gutterTreeNode.height += size;
          clone.gutterTreeNode._resize();
        }

      });
    });
  },

  duplicateClone: function() {


    if (!this._lastClicked) return;

    if (!this._lastClicked.getAttribute("tid")) {
      parus.parus8.errorMessage("Укажите таблицу, строку или столбец которой<br/>вы хотите размножить.");
      return;
    }

    var table = this._tables.byKey[this._lastClicked.getAttribute("tid")];

    if (!table) {
      parus.parus8.errorMessage("Укажите таблицу, строку или столбец которой<br/>вы хотите размножить.");
      return;
    }

    if (table.readOnly) {
      parus.parus8.errorMessage("Размножение строк или столбцов таблицы невозможно, т.к. таблица защищена от изменений");
      return;
    }

    if (!this._lastClicked.getAttribute("clid")) {
      parus.parus8.errorMessage("Укажите строку или столбец, который<br/>вы хотите размножить.");
      return;
    }

    var clone = table.clones.byKey[this._lastClicked.getAttribute("clid")];

    if (!clone) {
      parus.parus8.errorMessage("Эту строку или столбец размножить нельзя.");
      return;
    }

    this._expandTable(table);

    var newClone = table.placeClone();

    dojo.forEach(newClone._staticValues, dojo.hitch(this, function(staticValue, i) {
      staticValue.valueNode.innerHTML = clone._staticValues[i].valueNode.innerHTML;
    }));


    this.valueChanged();

    this.selectCell(newClone.cells[0]);
    this.focusTemplate();

    this.modified = true;
    this.onModified();

  },

  addClone: function() {
    if (!this._lastClicked) return;

    if (!this._lastClicked.getAttribute("tid")) {
      parus.parus8.errorMessage("Укажите таблицу, в которую вы <br/>хотите добавить строку или столбец.");
      return;
    }

    var table = this._tables.byKey[this._lastClicked.getAttribute("tid")];

    if (!table) {
      parus.parus8.errorMessage("Укажите таблицу, в которую вы <br/>хотите добавить строку или столбец.");
      return;
    }

    if (table.readOnly) {
      parus.parus8.errorMessage("Добавление строк или столбцов таблицы невозможно, т.к. таблица защищена от изменений");
      return;
    }

    this._expandTable(table);

    this.selectCell(table.placeClone().cells[0]);
    this.focusTemplate();

    this.valueChanged();

    this.modified = true;
    this.onModified();

  },

  addClones: function() {
    if (!this._lastClicked) return;

    if (!this._lastClicked.getAttribute("tid")) {
      parus.parus8.errorMessage("Укажите таблицу, в которую вы <br/>хотите добавить строки или столбцы.");
      return;
    }

    var table = this._tables.byKey[this._lastClicked.getAttribute("tid")];

    if (!table) {
      parus.parus8.errorMessage("Укажите таблицу, в которую вы <br/>хотите добавить строки или столбцы.");
      return;
    }

    if (table.readOnly) {
      parus.parus8.errorMessage("Добавление строк или столбцов таблицы невозможно, т.к. таблица защищена от изменений");
      return;
    }


    var dialog = new parus.balanceRowCountDialog({

      onApply: dojo.hitch(this, function() {

        this._expandTable(table);

        for (var i = 1; i <= dialog.rowCountEdit.value; i++)
        table.placeClone();

        this.valueChanged();

        this.selectCell(table.clones[table.clones.length - 1].cells[0]);
        this.focusTemplate();

        this.modified = true;
        this.onModified();


        return true;

      })

    });

    dialog.show();

  },

  deleteClones: function() {
    var clones = [];

    dojo.query(".templateGridSelectedCellBorder,.templateGridActiveCellBorder", this.templateNode).forEach(dojo.hitch(this, function(node) {
      var tid = node.getAttribute("tid");
      if (!tid) return;
      var clid = node.getAttribute("clid");
      if (!clid) return;
      var clone = this._tables.byKey[tid].clones.byKey[clid];
      if (clone) if (dojo.indexOf(clones, clone) < 0) clones.push(clone);
    }));

    if (!clones.length) {
      parus.parus8.errorMessage("Выделите область, включающую удаляемые строки.<br/>" + "Для этого щелкните по противоположному углу выделяемой области, придерживая клавишу Ctrl.");
      return;
    }

    dojo.forEach(clones, dojo.hitch(this, function(clone) {

      var table = clone.table;

      this._expandTable(table);

      clone.node.parentNode.removeChild(clone.node);

      if (clone.size) {
        this.shiftClones(table, clone.commonIndex, -clone.size)
        this.shiftParts(clone.table.part, -clone.size);
      }


      clone.table.offsetSize = clone.table.offsetSize - clone.size;

      clone.owner.clones.splice(dojo.indexOf(clone.owner.clones, clone), 1);
      delete clone.owner.clones.byKey[clone.rn];

      if (!table.clones.length) table.placeClone(null, true);

    }));

    this.valueChanged();

    this.modified = true;
    this.onModified();

  },

  checkValues: function() {

    this.performConfirmation(

    dojo.hitch(this, function() {

      var dialog;

      var rn = this.subreport || this.report;

      var params = {
        grid: null,
        kind: this.kind,
        isSubReport: this.section ? 1 : 0,
        rn: [this.section ? this.subreport : this.report],
        formedRn: [parus.parus8.nodeField(this.info, "EDITION")],
        reportRn: [this.report],
        title: ((this.kind == 0) ? "Первичные" : "Сводные") + " отчеты: Параметры проверки"
      };

      if (this.autonomousMode) dojo.mixin(params, {

        showProtocol: function() {
          if (parus.parus8._themeEditorMode) {
            alert("В режиме редактирования схемы это действие невозможно.");
            return;
          }

          parus.parus8.registerAction();

          var url = dojo.moduleUrl("parus", "checkreport.html").toString() + "?loggedUserHandler=" + parus.database.connected + "&params=" + parus.parus8.hexEncodeParams([
          dialog.kind, dialog.isSubReport, (dialog.showResultReportCheckBox.checked ? 1 : 0), dialog.rn[0], dialog.checks || ""]);
          window.open(url, "_blank");
        }
      });


      dialog = new parus.balanceCheckReportDialog(params);

      dialog.show();

    }), true);

  },

  checkReport: function() {
    if (this.autonomousMode && !parus.parus8._embeddedMode) {
      if (parus.parus8._themeEditorMode) {
        alert("В режиме редактирования схемы это действие невозможно.");
        return;
      }

      var url = dojo.moduleUrl("parus", "checkreport.html").toString() + "?loggedUserHandler=" + parus.database.connected + "&params=" + parus.parus8.hexEncodeParams([
      this.kind, this.section ? 1 : 0, 0, this.section ? this.subreport : this.report, ""]);
      window.open(url, "_blank");
      parus.parus8.registerAction();
    } else parus.balance.balanceShowCheckReportProtocol(
    null, this.kind, this.subreport, false, [this.subreport || this.report]);
  },

  getCell: function(id) {
    return this.pane._cells[id];
  },

  resolveCellIdent: function(Ident) {
    var result = null;
    dojo.forEach(this._staticValues, dojo.hitch(this, function(staticValue) {
      if ("ID_" + staticValue.balanceIndex == Ident) result = staticValue;
    }));
    return result;
  },


  loadDiagrams: function() {

    var diagramHolder;
    var menu;

    dojo.query("[rid='s']", this.templateNode).filter("[it='3']").forEach(dojo.hitch(this, function(diagram) {

      var refreshFunc = dojo.hitch(this, function() {
        this.performConfirmation(
        dojo.hitch(this, function() {


          var onload = dojo.connect(diagram, "onload", dojo.hitch(this, function() {

            dojo.disconnect(onload);
            diagram.src = parus.database.getDiagramUrl(this.template, this.report, this.subreport, diagram.getAttribute("idx"));

            if (diagramHolder) {
              diagramHolder.parentNode.removeChild(diagramHolder);
              diagramHolder = null;
            }
            dojo.connect(diagram, "ondblclick", refreshFunc);
            menu.bindDomNode(diagram);


          }));

          diagram.src = "../dojo/dojo/resources/blank.gif";

        }), true);

      });

      var menu = new dijit.Menu({
        "class": "balanceMenu"
      });

      menu.addChild(new dijit.MenuItem({
        label: "Обновить диаграмму",
        onClick: refreshFunc
      }));

      menu.startup();

      diagramHolder = document.createElement("div");

      dojo.style(diagramHolder, {
        position: diagram.style.position,
        left: diagram.style.left,
        top: diagram.style.top,
        width: diagram.style.width,
        height: diagram.style.height,
        zIndex: diagram.style.zIndex + 1,
        border: "1px solid black",
        opacity: "0.5",
        backgroundColor: "#A0A0A0",
        font: "bold 18px Tahoma, Verdana, sans-serif"
      });
      diagramHolder.align = "center";

      var labelDiv = diagramHolder.appendChild(document.createElement("div"));
      dojo.style(labelDiv, {
        color: "black",
        margin: "20px"
      });

      labelDiv.appendChild(document.createTextNode("Обновите диаграмму двойным щелчком."));
      diagram.parentNode.appendChild(diagramHolder);

      dojo.connect(diagramHolder, "ondblclick", refreshFunc);
      menu.bindDomNode(diagramHolder);


    }));

  },

  getCellValue: function(Row, Col, Ident, asString) {

    var valueNode;
    var cell;

    if (Row && Col) {
      var id = "R" + Row + "C" + Col;
      cell = this.getCell(id);
      valueNode = this.getValueNode(cell);
    }
    else if (Ident) {
      var staticValue = this.resolveCellIdent(Ident);
      if (staticValue) {
        valueNode = staticValue.valueNode;
        cell = staticValue.node;
      }
    };

    var text = parus.parus8.getTextContent(valueNode);

    if (!asString) {
      return dojo.number.parse(text) || 0;
    }
    else return text;
  },

  getCellNode: function(Row, Col, Ident) {

    var valueNode;
    var cell;

    if (Row && Col) {
      var id = "R" + Row + "C" + Col;
      cell = this.getCell(id);
    }
    else if (Ident) {
      var staticValue = this.resolveCellIdent(Ident);
      if (staticValue) {
        valueNode = staticValue.valueNode;
        cell = staticValue.node;
      }
    };

    return cell;
  },

  onLoad: function() {

    this.progressIndicate("Трафарет готовится....");

    var sheets = [];

    if (this.headingContentPane) {
      if (this.headingContentPane.actionsButton) this.headingContentPane.actionsButton.destroyRecursive();
      if (this.headingContentPane.toolbar) {
        this.headingContentPane.toolbar.destroyRecursive()
      }

      dojo.mixin(this.headingContentPane, {
        actionsButton: null,
        toolbar: null
      });

    };

    this._allValuesLoaded = false;
    this._staticValues = [];
    this.__staticValuesIndex = {};
    this._cells = {};
    this._tables = [];
    dojo.mixin(this._tables, {
      byKey: {}
    });

    this._parts = [];
    this.templateNode = null;
    this.gutterNode = null;
    this._gutterLevels = [];

    dojo.query("[rid='w']", this.containerNode).forEach(dojo.hitch(this, function(node) {
      if (!this.templateNode) {
        this.templateNode = node;
        this.templateNode.setAttribute("uid", this._cellnums++);
      }
      else {
        node.parentNode.removeChild(node);
        dojo.query("[cid]", node).forEach(function(node) {
          node.removeAttribute("cid")
        });
        sheets.push(node);
      }
    }));

    if (sheets.length) {

      var root = this.templateNode.parentNode;
      root.removeChild(this.templateNode);
      root.style.height = "100%";
      root.style.width = "100%";

      var html = [];
      html.push("<div dojoType=\"dijit.layout.TabContainer\" style=\"width:100%;height:100%\" tabPosition=\"bottom\">");

      html.push("<div class=\"balanceTemplateContentPaneContentOpaque\" dojoType=\"dijit.layout.ContentPane\" style=\"padding:0\" title=\"Трафарет\">");
      html.push("</div>");

      dojo.forEach(sheets, function(sheet) {
        html.push("<div class=\"balanceTemplateContentPaneContentOpaque\" dojoType=\"dijit.layout.ContentPane\" style=\"padding:0\" title=\"" + sheet.getAttribute("sheetname") + "\">");
        html.push("</div>");
      });

      html.push("</div>");

      dojo.place(html.join(""), root, "only");

      var parsed = dojo.parser.parse({
        rootNode: root,
        template: true
      });
      parsed[1].containerNode.appendChild(this.templateNode);

      for (var i = 2; i < parsed.length; i++)
      parsed[i].containerNode.appendChild(sheets[i - 2]);
    };

    if (!this.templateNode) {

      this.progressIndicate();

      dojo.fadeIn({
        node: this.domNode
      }).play();
      dojo.style(this.containerNode, {
        color: "red",
        fontSize: "200%",
        padding: "5px"
      });
      return;
    };

    this.templateNode.style.border = "1px solid #40407F";

    var moveAfterReturnDirectionAttr = this.templateNode.getAttribute("moveAfterReturnDirection");
    if (moveAfterReturnDirectionAttr == "left") this.moveAfterReturnDirection = 37;
    else if (moveAfterReturnDirectionAttr == "right") this.moveAfterReturnDirection = 39;
    else if (moveAfterReturnDirectionAttr == "up") this.moveAfterReturnDirection = 38;
    else this.moveAfterReturnDirection = 40;

    dojo.query("script", this.containerNode).forEach(dojo.hitch(this, function(item) {
      var script = (!dojo.isIE || dojo.isIE >= 10) ? item.textContent : item.innerHTML
      dojo.mixin(this, dojo.fromJson(script));
    }));

    if (this.fixedCols) if (this.fixedCols >= this.cols) this.fixedCols = 0;

    if (this.fixedRows) if (this.fixedRows >= this.rows) this.fixedRows = 0;

    this.loadCells();

    if (this.onInit) this.onInit();

    var staticValues;
    var tables;
    var tableValues;
    var remarks;


    this.progressIndicate("Загружаются значения....");

    var deflist = (new dojo.DeferredList([

    parus.database.query("ReportValues", {
      "TEMPLATE": this.template,
      "REPORT": this.report,
      "SUBREPORT": this.subreport
    }, function(response) {
      staticValues = response
    }), parus.database.query("TemplateTables", {
      "TEMPLATE": this.template
    }, function(response) {
      tables = response
    }), parus.database.queryObject("TableValues", {
      "TEMPLATE": this.template,
      "REPORT": this.report,
      "SUBREPORT": this.subreport
    }, function(response) {
      tableValues = response
    }),

    parus.database.query("valuesRemarks", {
      "TEMPLATE": this.template,
      "REPORT": this.report,
      "SUBREPORT": this.subreport
    }, function(response) {
      remarks = response
    }),

    parus.database.execute("GetReportInfo", {
      "REPORT": this.report,
      "SUBREPORT": this.subreport,
      "TEMPLATE": this.template
    }, dojo.hitch(this, function(response) {
      this.info = parus.parus8.rowNodes(response)[0];


      this.formCode = parus.parus8.nodeField(this.info, "FORM_CODE");
      this.agent = parus.parus8.nodeField(this.info, "AGENT");
      this.section = parus.parus8.nodeField(this.info, "SECTION");
      this.kind = parus.parus8.nodeField(this.info, "KIND");
      this.reportDate = parus.parus8.nodeField(this.info, "BDATE");
      this.direction = parus.parus8.nodeField(this.info, "DIRECT_TABLE");
      this.subreport = this.subreport || parus.parus8.nodeField(this.info, "SUBREPORT_RN");
      this.username = parus.parus8.nodeField(this.info, "USERNAME");
      this.ignoreWarnings = parus.parus8.nodeField(this.info, "IGNORE_WARNINGS") == "1";

      if (!this.title) this.attr("title", parus.balance.describeReport(this.report, this.subreport, this.template, null, null, null, null, 0));

    }))


    ])).addCallback(
    dojo.hitch(this, function() {

      this.defaultZoom = this.defaultZoom || 100;
      if (this.defaultZoom != 100) {
        this.zoom = this.defaultZoom / 100;
        this._zoomChanged();
      };

      this.readonly = (parus.parus8.nodeField(this.info, "FORCEREADONLY")) == "1";
      this.useHistory = parus.parus8.nodeField(this.info, "USE_HISTORY");

      if (this.readonly && !this.autonomousMode) this.headingContentPane.containerNode.firstChild.appendChild(document.createTextNode(String.fromCharCode(160) + "(только чтение)"));

      var menu = this.createPopupMenu();
      parus.balance._createActionsButton(menu, this.headingContentPane);
      menu.bindDomNode(this.domNode);

      var settings = parus.userdata.get(this.declaredClass + this.kind);

      if (settings) {
        parus.gridSettingsDialog.mergeMenuSettings(menu, settings.actionSettings, settings.userProcsActions, settings.userReportsActions, settings.userAppsActions);
      }

      this.progressIndicate("Готовятся значения показателей....");

      this._monitorChanges = true;

      this.loadStaticValues(staticValues);

      this.progressIndicate("Готовятся таблицы....");

      this.loadTables(parus.xml.fromXml(tables), tableValues);

      this.loadDiagrams();

      if (this.formulas) {

        this.progressIndicate("Готовятся формулы....");

        dojo.mixin(this.formulas, new parus.templateGridPaneFormulasMixin());
        dojo.mixin(this.formulas, {
          pane: this,
          getCell: dojo.hitch(this, this.getCell),
          getCellValue: dojo.hitch(this, this.getCellValue),
          getCellNode: dojo.hitch(this, this.getCellNode),
          getValueNode: dojo.hitch(this, this.getValueNode),
          resolveCellIdent: dojo.hitch(this, this.resolveCellIdent)
        });
        if (this.dependencies) this.formulas.calcAll(this.dependencies);

        if (this.formatConditions) for (var formatCondition in this.formatConditions) dojo.hitch(this.formulas, this.formatConditions[formatCondition])();
      };


      this.templateNode.insertAdjacentHTML("beforeend", "<input rid='f' type='checkbox' style='position: absolute;left:-150px;top:-150px'/>");
      this.templateNode.insertAdjacentHTML("beforeend", "<textarea rid='clp' style='position: absolute;left:-150px;top:-150px'/>");

      this.focusNode = dojo.query("[rid='f']", this.templateNode)[0];
      this.clipboardNode = dojo.query("[rid='clp']", this.templateNode)[0];

      var container = this.domNode.parentNode.parentNode;
      var hidden = dojo.hasClass(container, "dijitHidden");

      if (hidden) dojo.removeClass(container, "dijitHidden");



      if (!(dojo.isIE <= 6)) {
        for (var key in this._changedCells) {
          var cell = this._changedCells[key];
          //            if (cell.getAttribute("wt") && !cell.getAttribute("clid"))
          this.checkCellHeight(cell, null, true, null, true);
        }
        //        this.drawAllCanvas();
      }

      this._monitorChanges = false;
      this._changedCells = null;

      if (hidden) dojo.addClass(container, "dijitHidden");

      this.progressIndicate("Готовятся примечания....");

      this._remarksStore = new parus.gridData({
        persistent: true,
        _data: parus.parus8.rowNodes(remarks)
      });

      dojo.forEach(this._remarksStore._data, dojo.hitch(this, this.applyRemarkColor));

      if (this.remarksShown) this.showRemarksPopups();

      this.progressIndicate("Последние приготовления....");

      this.__fireDefferedAttrs();

      if (!this.gutterNode && this.gutterSize && (this.direction == "0")) {

        this.gutterNode = document.createElement("div");
        this.gutterNode.className = "gutterPane";
        this.templateNode.parentNode.appendChild(this.gutterNode);

        if (this.direction == "0") {
          this.templateNode.style.left = (this.gutterSize + 1) + "px";
          dojo.style(this.gutterNode, {
            width: this.gutterSize + "px",
            height: this.templateNode.style.height
          });
        }
        else {
          this.templateNode.style.top = (this.gutterSize + 1) + "px";
          dojo.style(this.gutterNode, {
            height: this.gutterSize + "px",
            width: this.templateNode.style.width
          });
        }

        setTimeout(dojo.hitch(this, this.buildGutterTree), 100);
        this._forceScrollGutter = !! sheets.length;
      };

      dojo.connect(this.focusNode, "onkeydown", this, this.keyDown);


      if (this.fixedCols || this.fixedRows || this.gutterNode) dojo.connect(this.templateNode.parentNode, "onscroll", this, this._doscroll);

      this.modified = false;
      this.onModified();

      dojo.fadeIn({
        node: this.domNode,
        onEnd: dojo.hitch(this, function() {
          this._allValuesLoaded = true;
          this.drawAllCanvas();

          this.progressIndicate();

          var cells = dojo.query("[ids]", this.templateNode);
          if (cells.length) this.selectCell(cells[0]);

          dijit.focus(this.focusNode);
          if (this.onDone) this.onDone(this);

          if (this.readonly) parus.parus8.notificationMessage("Отчет открыт в режиме \"только для чтения\",<br/> изменения значений показателей сохраняться не будут.", dojo.hitch(this, function() {
            this.focusTemplate();
          })

          );

          this.focusTemplate();

        })
      }).play();

      return true;
    }));
  },

  buildGutterTree: function() {
    dojo.empty(this.gutterNode);

    dojo.forEach(this._gutterLevels, function(gutterLevel) {
      gutterLevel.destroyRecursive();
    });

    this._gutterLevels = [];

    for (var i = 0; i < this._maxTotalLevel + 1; i++) {

      var lvl = new parus.templateGridPane.gutterTreeLevel({
        level: i,
        pane: this
      }, this.gutterNode.appendChild(document.createElement("div")));

      this._gutterLevels.push(lvl);
    }

    dojo.forEach(this._tables, dojo.hitch(this, function(table) {
      if (!table.clones.length) return;
      if (table.clones[0].uninitialized) return;

      var gutter = new parus.templateGridPane.verticalGutterTreeNode({

        height: parus.parus8.styleSize(table.part.node.style.height),
        top: parus.parus8.styleSize(table.part.node.style.top),
        pane: this,
        table: table

      }, this.gutterNode.appendChild(document.createElement("div")));

      table.gutterTreeNode = gutter;

      dojo.forEach(table.totals, dojo.hitch(this, function(total) {
        dojo.forEach(total.clones, dojo.hitch(this, function(clone) {


          var children = clone.treeChildren || [];
          if (!children.length) return;

          var h = clone.size;
          var t = parus.parus8.styleSize(clone.node.style.top);

          dojo.forEach(children, function(child) {
            h += child.size;
            if (total.location == "0") t -= child.size;
          });

          var gutter = new parus.templateGridPane.verticalGutterTreeNode({

            height: h,
            top: (t + parus.parus8.styleSize(clone.part.node.style.top)),
            left: total.level * 20,
            pane: this,
            clone: clone

          }, this.gutterNode.appendChild(document.createElement("div")));

          clone.gutterTreeNode = gutter;

        }));
      }));
    }));
  },

  _doscroll: function(event) {
    var node = this.templateNode.parentNode;
    if (!node) return;
    var zoom = this.zoom;
    if (this.direction == "0") {
      if (this.gutterNode && this._forceScrollGutter) this.gutterNode.style.top = (-node.scrollTop / zoom) + "px";

      if (this.gutterNode) {
        dojo.query("*.gutterLevelIndex", this.gutterNode).forEach(dojo.hitch(this, function(node) {

          dojo.animateProperty({
            node: node,
            duration: 200,
            properties: {
              top: {
                end: this.gutterNode.parentNode.scrollTop,
                unit: "px"
              }
            }
          }).play();

        }));
      };



      if (this.fixedRows) this._parts[0].node.style.top = (node.scrollTop / zoom) + "px";
      if (this.fixedCols) {
        var sc = parseInt(node.scrollLeft) / zoom;
        dojo.query("[fo]", this.containerNode).forEach(function(cell) {
          cell.style.left = (sc + parseInt(cell.getAttribute("fo"))) + "px";
        });
      }
    }
    else {

      if (this.fixedCols) this._parts[0].node.style.left = (node.scrollLeft / zoom) + "px";
      if (this.fixedRows) {
        var sc = parseInt(node.scrollTop) / zoom;
        dojo.query("[fo]", this.containerNode).forEach(function(cell) {
          cell.style.top = (sc + parseInt(cell.getAttribute("fo"))) + "px";
        });
      }
    }

  },

  _focusTemplateID: null,

  focusTemplate: function() {
    if (this._focusTemplateID) clearTimeout(this._focusTemplateID);
    this._focusTemplateID = setTimeout(dojo.hitch(this, function() {
      if (!this.autonomousMode) {
        var parent = dijit.getEnclosingWidget(this.domNode.parentNode);
        if (parent) {
          var aparent = dijit.getEnclosingWidget(parent.domNode.parentNode);
          if (aparent) {
            var bparent = dijit.getEnclosingWidget(aparent.domNode.parentNode);
            if (bparent) {
              if (bparent.selectedChildWidget != aparent) {
                return;
              }
            }
          }
        }
      }

      if (!this.editing) {
        var focusNode = this.focusNode;
        if (focusNode && focusNode.focus) {
          try {
            if (dojo.isFF) {
              var x = this.containerNode.scrollTop;
              focusNode.focus({
                preventScroll: true
              });
              this.containerNode.scrollTop = x;
            }
            else focusNode.focus({
              preventScroll: true
            });
          } catch (e) {};
        }
      }
      //if (dojo.isIE <= 8) setTimeout(dojo.hitch(this, this.focusTemplate), 100);
    }), 100);
  },


  cellShiftedAddress: function(cell) {


    var part = this._parts[cell.getAttribute("pid")];
    var addr = cell.getAttribute("cid").toString().match(/^R(\d+)C(\d+)$/);

    var r = 0;
    var c = 0;

    if (this.direction == "0") {

      c = addr[2];

      dojo.forEach(this._parts, function(apart) {
        if (apart.index < part.index) {
          if (apart.table) {
            dojo.forEach(apart.table.clones, function(clone) {
              r += clone.cellsize;
            });

            dojo.forEach(apart.table.totals, function(total) {
              dojo.forEach(total.clones, function(clone) {
                r += clone.cellsize;
              });
            });

          }
          else r += apart.height;
        }
      });

      if (part.table) {
        var clid = cell.getAttribute("clid");
        var ttid = cell.getAttribute("ttid");
        var clone = (ttid == part.table.rn) ? part.table.clones.byKey[clid] : part.table.totals.byKey[ttid].clones.byKey[clid]
        var total = (ttid == part.table.rn) ? null : part.table.totals.byKey[ttid];

        dojo.forEach(part.table.clones, function(aclone) {
          if (aclone.commonIndex < clone.commonIndex) r += aclone.cellsize;
        });

        dojo.forEach(part.table.totals, function(total) {
          dojo.forEach(total.clones, function(aclone) {
            if (aclone.commonIndex < clone.commonIndex) r += aclone.cellsize;
          });
        });

        if (total) {
          r += (addr[1] - total.row) + 1;
        }
        else {
          dojo.forEach(part.table.totals, function(total) {
            if (total.row < addr[1]) r -= total.height;
          });
          r += (addr[1] - part.row) + 1;
        }
      }
      else {
        r += (addr[1] - part.row) + 1;
      }

    }
    else {


      r = addr[1];

      dojo.forEach(this._parts, function(apart) {
        if (apart.index < part.index) {
          if (apart.table) {
            dojo.forEach(apart.table.clones, function(clone) {
              c += clone.cellsize;
            });

            dojo.forEach(apart.table.totals, function(total) {
              dojo.forEach(total.clones, function(clone) {
                c += clone.cellsize;
              });
            });

          }
          else c += apart.width;
        }
      });

      if (part.table) {
        var clid = cell.getAttribute("clid");
        var ttid = cell.getAttribute("ttid");
        var clone = (ttid == part.table.rn) ? part.table.clones.byKey[clid] : part.table.totals.byKey[ttid].clones.byKey[clid]
        var total = (ttid == part.table.rn) ? null : part.table.totals.byKey[ttid];

        dojo.forEach(part.table.clones, function(aclone) {
          if (aclone.commonIndex < clone.commonIndex) c += aclone.cellsize;
        });

        dojo.forEach(part.table.totals, function(total) {
          dojo.forEach(total.clones, function(aclone) {
            if (aclone.commonIndex < clone.commonIndex) c += aclone.cellsize;
          });
        });

        if (total) {
          c += (addr[2] - total.col) + 1;
        }
        else {
          dojo.forEach(part.table.totals, function(total) {
            if (total.col < addr[2]) c -= total.width;
          });с += (addr[2] - part.col) + 1;
        }
      }
      else {
        c += (addr[2] - part.col) + 1;
      }

    }

    return {
      r: r,
      c: c
    };

  },

  _lastKeyEvent: null,

  keyDown: function(evt) {

    if (this._lastKeyEvent && (this._lastKeyEvent == evt.timeStamp)) return;

    if (!this._lastClicked) return;

    parus.parus8.registerAction();

    var direction;

    if (((evt.keyCode == 67) && evt.ctrlKey) || ((evt.keyCode == 45) && evt.ctrlKey)) {
      this.copySelection();
      return;
    }

    if ((evt.keyCode == 37) || (evt.keyCode == 9 && evt.shiftKey)) {
      direction = "left";
    }
    else if (evt.keyCode == 38) {
      direction = "top";
    }
    else if ((evt.keyCode == 39) || (evt.keyCode == 9 && !evt.shiftKey)) {
      direction = "right";
    }
    else if (evt.keyCode == 40) {
      direction = "bottom";
    }
    else {
      this._lastClicked.click();
      return;
    }

    var cell = this._neighbor(this._lastClicked, direction);

    if (!cell && (evt.keyCode == 9)) cell = this._lastClicked;

    this._lastKeyEvent = evt.timeStamp;

    if (cell) {
      this.followCell(cell);
      if (evt.preventDefault) evt.preventDefault();
      if (evt.stopPropagation) evt.stopPropagation();
      evt.cancelBubble = true;
      evt.keyCode = 0;
      return false;
    }

  },

  followCell: function(cell) {
    this.selectCell(cell);
    this.focusTemplate();
    dojo.window.scrollIntoView(cell);

    if (this.fixedCols || this.fixedRows)

    setTimeout(dojo.hitch(this, function() {
      var coords = dojo.coords(cell);
      var fixedCoords = dojo.coords(this._parts[0].node);
      if (this.direction == "0") {
        if (this.fixedRows) if (coords.y < fixedCoords.y + fixedCoords.h) {
          this.containerNode.scrollTop = this.containerNode.scrollTop - (fixedCoords.y + fixedCoords.h - coords.y);
        }
      }
      else {
        if (this.fixedCols) if (coords.x < fixedCoords.x + fixedCoords.w) {
          this.containerNode.scrollLeft = this.containerNode.scrollLeft - (fixedCoords.x + fixedCoords.w - coords.x);
        }
      }
    }), 1);



  },

  onModified: function() {
    //to be overriden
  },

  onTitleChanged: function() {
    //to be overriden
  },

  _confirmed: false,

  onClose: function() {


    if (this.editing) {
      if (!this.editing.postValue()) {
        if (this.editing.cancelValue) this.editing.cancelValue();
        else return false;
      }
    };

    var action = dojo.hitch(this, function() {
      this._confirmed = true;

      if (parus.parus8._embeddedMode) {
        parus.embeddedMode.closeTab();
      } else {
        parus.balance.TabContainer.selectChild((this.kind == "0") ? parus.balance.primaryPage : parus.balance.consolidatedPage, false);
        if (parus.balance.TabContainer) parus.balance.TabContainer.removeChild(this.parentPane);
      }
    });

    if (this._confirmed) return true;

    if (!this.modified) {
      action();
      return false;
    }

    (new parus.confirmationDialog({
      message: "Вы закрываете вкладку с измененными значениями показателей. <br/>Сохранить сделанные Вами изменения?",

      onShow: function() {
        this.cancelButton.domNode.style.display = "";
        this.noButton.onClick = dojo.hitch(this, function() {
          action();
          this.close();
        })
      },

      onApply: dojo.hitch(this, function() {
        if (this.useHistory == "2")(new parus.confirmationDialog({
          message: "Сохранить историю значений?",
          onApply: dojo.hitch(this, function() {
            this.saveHistory(dojo.hitch(this, function() {
              this.saveValues(false, action);
            }));
            return true;
          }),
          onClose: dojo.hitch(this, function(dialog) {
            if (!dialog.applied) this.saveValues(false, action);
          })
        })).show();
        else if (this.useHistory == "1") {
          this.saveHistory(dojo.hitch(this, function() {
            this.saveValues(false, action);
          }));
        }
        else this.saveValues(false, action);
        return true;
      })

    })).show();

    this._confirmed = false;
    return false;

  },

  valueChanged: function(addr) {

    var deps = [];

    dojo.forEach(this.dependencies["*"], dojo.hitch(this, function(dependency) {
      deps.push(dependency);
    }));

    if (addr) {
      (dojo.hitch(this, function(addr) {
        if (dojo.indexOf(deps, addr) == -1) {
          deps.push(addr);
          dojo.forEach(this.dependencies[addr], dojo.hitch(this, arguments.callee));
          dojo.forEach(this.pane.dependencies[addr], dojo.hitch(this, arguments.callee));
        }
      }))(addr);
    }
    else if (!this.table) {
      dojo.forEach(this._staticValues, dojo.hitch(this, function(staticValue) {

        (dojo.hitch(this, function(addr) {
          if (dojo.indexOf(deps, addr) == -1) {
            deps.push(addr);
            dojo.forEach(this.dependencies[addr], dojo.hitch(this, arguments.callee));
            dojo.forEach(this.pane.dependencies[addr], dojo.hitch(this, arguments.callee));
          }
        }))(staticValue.id);

      }));
    };

    deps = this.formulas.tossDependencies(this.dependencies, deps);

    dojo.forEach(deps, dojo.hitch(this, function(dependency) {
      var d = this.formulas[dependency];
      if (d) this.pane.setCellText(this.getCell(dependency), null, dojo.hitch(this.formulas, d)());
      else {
        d = this.pane.formulas[dependency];
        if (d) this.pane.setCellText(this.pane.getCell(dependency), null, dojo.hitch(this.pane.formulas, d)());
      };

      d = this.formatConditions[dependency] || this.pane.formatConditions[dependency];
      if (d) dojo.hitch(this.formulas, d)();
      else {
        d = this.pane.formatConditions[dependency];
        if (d) dojo.hitch(this.pane.formulas, d)();
      };


      if (this._tables) {
        d = this._tables.byKey[dependency];
        if (d) {
          if (!d.cells.byID[addr]) {
            dojo.forEach(d.clones, function(clone) {
              clone.calcAll()
            });
            dojo.forEach(d.totals, function(total) {
              dojo.forEach(total.clones, function(clone) {
                clone.calcAll();
              })
            });
          }
        };
      };

    }));

    if (this.table) this.pane.valueChanged(addr);

  },

  cellCoords: function(startCol, startRow, endCol, endRow) {
    var result = {
      l: 0,
      t: 0,
      w: 0,
      h: 0
    };
    for (var i = 0; i < startCol - 1; i++)
    result.l += this.widths[i];
    for (var i = 0; i < startRow - 1; i++)
    result.t += this.heights[i];
    for (var i = startCol; i <= endCol; i++)
    result.w += this.widths[i - 1];
    for (var i = startRow; i <= endRow; i++)
    result.h += this.heights[i - 1];
    return result;
  },

  shiftParts: function(part, size, deferred) {

    if (deferred) {


      if (this.direction == "0") {

        this.__setDefferedAttr(part.node, "dh", size);
        for (var i = part.index + 1; i < this._parts.length; i++)
        this.__setDefferedAttr(this._parts[i].node, "dy", size);
        this.__setDefferedAttr(this.templateNode, "dh", size);
        if (this.gutterNode) this.__setDefferedAttr(this.gutterNode, "dh", size);

      }
      else {

        this.__setDefferedAttr(part.node, "dw", size);
        for (var i = part.index + 1; i < this._parts.length; i++)
        this.__setDefferedAttr(this._parts[i].node, "dx", size);
        this.__setDefferedAttr(this.templateNode, "dw", size);
        if (this.gutterNode) this.__setDefferedAttr(this.gutterNode, "dw", size);
      }

    }
    else {

      if (this.direction == "0") {
        dojo.style(part.node, {
          height: (parus.parus8.styleSize(part.node.style.height) + size) + "px"
        });

        if (part.table) if (part.table.gutterTreeNode) {
          part.table.gutterTreeNode.height = part.table.gutterTreeNode.height + size;
          part.table.gutterTreeNode._resize();
        }

        for (var i = part.index + 1; i < this._parts.length; i++) {

          dojo.style(this._parts[i].node, {
            top: (parus.parus8.styleSize(this._parts[i].node.style.top) + size) + "px"
          });

          if (this._parts[i].table) {

            dojo.forEach(this._parts[i].table.totals, function(total) {
              dojo.forEach(total.clones, function(clone) {
                if (!clone.gutterTreeNode) return;
                clone.gutterTreeNode.top += size;
                clone.gutterTreeNode._resize();
              });
            });


            if (this._parts[i].table.gutterTreeNode) {
              this._parts[i].table.gutterTreeNode.top += size;
              this._parts[i].table.gutterTreeNode._resize();
            }

          }
        }

        dojo.style(this.templateNode, {
          height: (parus.parus8.styleSize(this.templateNode.style.height) + size) + "px"
        });

        if (this.gutterNode) dojo.style(this.gutterNode, {
          height: (parus.parus8.styleSize(this.gutterNode.style.height) + size) + "px"
        });


      }
      else {

        dojo.style(part.node, {
          width: (parus.parus8.styleSize(part.node.style.width) + size) + "px"
        });

        for (var i = part.index + 1; i < this._parts.length; i++)
        dojo.style(this._parts[i].node, {
          left: (parus.parus8.styleSize(this._parts[i].node.style.left) + size) + "px"
        });

        dojo.style(this.templateNode, {
          width: (parus.parus8.styleSize(this.templateNode.style.width) + size) + "px"
        });

        if (this.gutterNode) dojo.style(this.gutterNode, {
          width: (parus.parus8.styleSize(this.gutterNode.style.width) + size) + "px"
        });

      }
    }
  },


  __clone: function(rn, uninitialized) {

    var freeClone = false;

    if (!rn) {
      freeClone = true;
      rn = 1;
      dojo.forEach(this.clones, function(clone) {
        if (clone) if (clone.rn >= rn) rn = clone.rn + 1;
      });

      dojo.forEach(this.totals, function(total) {
        if (total) dojo.forEach(total.clones, function(clone) {
          if (clone) if (clone.rn >= rn) rn = clone.rn + 1;
        });
      });

    };

    this.table.commonCounter++;

    var clone = {
      rn: rn,
      freeClone: freeClone,
      table: this.table,
      owner: this,
      cells: [],
      _staticValues: [],
      size: this.table.size,
      cellsize: this.table.cellsize,
      pane: this.pane,
      part: this.table.part,
      commonIndex: this.table.commonCounter,
      formulas: dojo.clone(this.table.formulas),
      formatConditions: dojo.clone(this.table.formatConditions),
      dependencies: dojo.clone(this.table.dependencies),
      getValueNode: dojo.hitch(this.pane, this.pane.getValueNode),
      node: document.createElement("div"),
      uninitialized: uninitialized
    };

    dojo.mixin(clone, new parus.templateGridPaneCloneMixin());
    dojo.mixin(clone.formulas, new parus.templateGridPaneFormulasMixin());
    dojo.mixin(clone.cells, {
      byKey: {},
      byId: {}
    });
    dojo.mixin(clone._staticValues, {
      byKey: {}
    });

    dojo.mixin(clone.formulas, {
      pane: this.pane,
      getValueNode: dojo.hitch(this.pane, this.pane.getValueNode),
      getCell: dojo.hitch(clone, clone.getCell),
      getCellValue: dojo.hitch(clone, clone.getCellValue),
      getCellNode: dojo.hitch(clone, clone.getCellNode),
      resolveCellIdent: dojo.hitch(clone, clone.resolveCellIdent)
    });


    var innerHTML = "";
    clone.node.setAttribute("uid", this.pane._cellnums++);

    dojo.forEach(this.table.cells, dojo.hitch(this, function(cell) {
      var left = cell.left;
      var top = cell.top;
      innerHTML = innerHTML + "<div " + "tid='" + cell.tid + "' " + "trow='" + cell.trow + "' " + "tcol='" + cell.tcol + "' " + "clid='" + clone.rn + "' " + "ttid='" + this.rn + "' " + "uid='" + this.pane._cellnums+++"' " + "style='left:" + left + "px;" + "top:" + top + "px;" + (cell.fixed ? "z-index:10" : "") + "'" + cell.HTML;
    }));

    clone.node.innerHTML = innerHTML;

    var nodes = clone.node.childNodes;
    var pane = this.table.pane;
    for (var i = 0; i < nodes.length; i++) {

      var cloneCell = nodes[i];

      dojo.connect(cloneCell, "onclick", function(evt) {
        evt = evt || event;
        parus.parus8.registerAction();
        pane.selectCell(this, ( !! evt.shiftKey) || ( !! evt.altKey) || ( !! evt.ctrlKey));
        if (!evt.shiftKey && !evt.altKey && !evt.ctrlKey) pane.focusTemplate();
      }, cloneCell);

      clone.cells.push(cloneCell);
      clone.cells.byKey["R" + cloneCell.getAttribute("trow") + "C" + cloneCell.getAttribute("tcol")] = cloneCell;
      clone.cells.byId[cloneCell.getAttribute("cid")] = cloneCell;

    }

    if (this.totalkey) {

      if (this.table.pane.direction == "0") {
        for (var j = this.table.col - 1; j < this.table.col + this.table.width - 1; j++) {

          var cellObj = null;

          dojo.forEach(this.cells, function(cell) {
            if (cell.tcol.toString() == j.toString()) {
              cellObj = cell;
            }
          });

          for (var i = 0; i < nodes.length; i++)
          if (nodes[i].getAttribute("tcol").toString() == j.toString()) if (cellObj) {
            var trow = parseInt(nodes[i].getAttribute("trow")) || 0;
            var rcnt = parseInt(nodes[i].getAttribute("rcnt")) || 1;
            var cid = nodes[i].getAttribute("cid");
            delete clone.formulas[cid];
            var frm = this.table.formulas[cellObj.cid];
            if (frm) clone.formulas[cid] = this.pane.__makeFormula(frm, this.pane.__parseCellId(cid).row - this.pane.__parseCellId(cellObj.cid).row, 0);
            var s = 0;
            for (k = 0; k <= (rcnt - 1); k++)
            s = s + this.pane.heights[this.table.row + trow - 1 + k];
            nodes[i].style.height = s + "px";
            if (cellObj.className) nodes[i].className = cellObj.className;
            if (cellObj.readOnly) nodes[i].setAttribute("ro", "1")
            else nodes[i].removeAttribute("ro");
            if (cellObj.wordWrap) nodes[i].setAttribute("wt", "1")
            else nodes[i].removeAttribute("wt");
            nodes[i].innerHTML = cellObj.innerHTML;
            dojo.query("canvas[height]", nodes[i]).forEach(function(canvas) {
              canvas.height = (s - 4);
              canvas.parentNode.style.height = (s - 4) + "px";
            });
          }
          else nodes[i].style.display = "none";
        }
      }
      else {

        for (var j = this.table.row - 1; j < this.table.row + this.table.height - 1; j++) {

          var cellObj = null;

          dojo.forEach(this.cells, function(cell) {
            if (cell.trow.toString() == j.toString()) {
              cellObj = cell;
            }
          });

          for (var i = 0; i < nodes.length; i++)
          if (nodes[i].getAttribute("trow").toString() == j.toString()) if (cellObj) {
            var tcol = parseInt(nodes[i].getAttribute("tcol")) || 0;
            var ccnt = parseInt(nodes[i].getAttribute("ccnt")) || 1;
            var cid = nodes[i].getAttribute("cid");
            delete clone.formulas[cid];
            var frm = this.table.formulas[cellObj.cid];
            if (frm) clone.formulas[cid] = this.pane.__makeFormula(frm, 0, this.pane.__parseCellId(cid).col - this.pane.__parseCellId(cellObj.cid).col);
            var s = 0;
            for (k = 0; k <= (ccnt - 1); k++)
            s = s + this.pane.widths[this.table.col + tcol - 1 + k];
            nodes[i].style.width = s + "px";
            if (cellObj.className) nodes[i].className = cellObj.className;
            if (cellObj.readOnly) nodes[i].setAttribute("ro", "1")
            else nodes[i].removeAttribute("ro");
            if (cellObj.wordWrap) nodes[i].setAttribute("wt", "1")
            else nodes[i].removeAttribute("wt");
            nodes[i].innerHTML = cellObj.innerHTML;
            dojo.query("canvas[width]", nodes[i]).forEach(function(canvas) {
              canvas.width = (s - 4);
              canvas.parentNode.style.width = (s - 4) + "px";
            });
          }
          else nodes[i].style.display = "none";
        }
      }
    };

    var coords;

    if (this.table.pane.direction == "0") coords = {
      t: this.table.offsetSize,
      h: clone.size,
      l: 0,
      w: this.pane.templateWidth
    }
    else coords = {
      t: 0,
      h: this.pane.templateHeight,
      l: this.table.offsetSize,
      w: clone.size
    };

    dojo.style(clone.node, {
      width: coords.w + "px",
      height: coords.h + "px",
      left: coords.l + "px",
      top: coords.t + "px",
      margin: 0,
      padding: 0,
      position: "absolute",
      overflow: "hidden"
    });

    this.table.offsetSize += clone.size;

    this.table.part.node.appendChild(clone.node);

    if (!uninitialized)

    dojo.forEach(this.table.indexes, dojo.hitch(this, function(index) {

      var cell = clone.cells.byKey["R" + index.row + "C" + index.col];

      if (!cell) return;


      var staticValue = new parus.templateGridPaneInplaceEditor({
        id: cell.getAttribute("cid"),
        pane: this.pane,
        value: index.value || "",
        minVal: index.minVal,
        maxVal: index.maxVal,
        trim: index.trim,
        dataType: index.dataType,
        strLen: index.strLen,
        intPart: index.intPart,
        fracPart: index.fracPart,
        regExp: index.regExp,
        nullable: index.nullable,
        dictCheck: index.dictCheck,
        col: this.col + index.col + 1,
        row: this.row + index.row + 1,
        dictionary: index.dictionary,
        dicts: dojo.clone(index.dicts),
        dictNote: index.dictNote,
        balanceIndex: index.rn,
        valueChanged: dojo.hitch(clone, this.table.pane.valueChanged)
      });

      var node = cell;

      this.pane.__staticValuesIndex[node.getAttribute("uid")] = staticValue;

      var canEdit = !(this.pane.readonly) && !(node.getAttribute("ro")) && !(this.pane.formulas[staticValue.id]);

      if (canEdit) node.style.cursor = dojo.isIE ? "hand" : "pointer";

      dojo.mixin(staticValue, {
        node: node,
        canEdit: canEdit,
        valueNode: this.pane.getValueNode(node),
        connection: canEdit ? dojo.connect(node, "onclick", dojo.hitch(staticValue, staticValue.clickHandler)) : null
      });

      cell.setAttribute("iid", index.rn);

      if (freeClone && index.value) this.pane.setCellText(node, staticValue.valueNode, index.value);

      clone._staticValues.push(staticValue);
      clone._staticValues.byKey[staticValue.balanceIndex] = staticValue;

    }));

    this.clones.push(clone);
    this.clones.byKey[clone.rn] = clone;

    if (freeClone) {
      clone.calcAll();
      this.pane.shiftParts(this.table.part, clone.size, false);
    }

    if (uninitialized) {
      dojo.query("[class]", clone.node).forEach(function(node) {
        if (node.getAttribute("tid")) {
          var c = (parseInt(node.getAttribute("tcol")) || 0) + 1;
          var r = (parseInt(node.getAttribute("trow")) || 0) + 1;

          if (clone.table.pane.direction == "0") {
            if ((clone.table.col <= c) && ((clone.table.col + clone.table.width - 1) >= c)) dojo.addClass(node, "uninitializedTable");
          }
          else {
            if ((clone.table.row <= r) && ((clone.table.row + clone.table.height - 1) >= r)) dojo.addClass(node, "uninitializedTable");
          }
        }
      });

    }
    else dojo.forEach(this.clones, dojo.hitch(this, function(clone) {
      if (clone)

      if (clone.uninitialized) {

        clone.node.parentNode.removeChild(clone.node);

        if (clone.size) {
          this.pane.shiftClones(clone.table, clone.commonIndex, -clone.size)
          this.pane.shiftParts(clone.table.part, -clone.size);
        }

        clone.table.offsetSize = clone.table.offsetSize - clone.size;

        clone.owner.clones.splice(dojo.indexOf(clone.owner.clones, clone), 1);
        delete clone.owner.clones.byKey[clone.rn];
      }
    }));



    return clone;
  },

  __createTemplate: function(offset, cellsoffset) {

    var tablecoords = this.pane.cellCoords(this.table.col, this.table.row, this.table.col + this.table.width - 1, this.table.row + this.table.height - 1);
    var coords = this.pane.cellCoords(this.col, this.row, this.col + this.width - 1, this.row + this.height - 1);

    var params = (this.pane.direction == "0") ? {
      col: 1,
      row: this.row,
      width: this.pane.cols,
      height: this.height,
      dx: 0,
      dy: coords.t - tablecoords.t + offset,
      coloffset: 0,
      rowoffset: cellsoffset
    } : {
      col: this.col,
      row: 1,
      width: this.width,
      height: this.pane.rows,
      dx: coords.l - tablecoords.l + offset,
      dy: 0,
      coloffset: cellsoffset,
      rowoffset: 0
    };

    var nativeDependencies = dojo.clone(this.pane.dependencies);

    for (var i = params.col; i < params.col + params.width; i++)
    for (var j = params.row; j < params.row + params.height; j++) {
      var id = "R" + j + "C" + i;

      var cell = this.pane._cells[id];
      if (cell) {

        var trow = j - params.row + params.rowoffset;
        var tcol = i - params.col + params.coloffset;

        dojo.forEach(this.indexes, function(index) {
          if ((tcol == index.col) && (trow == index.row)) {
            if (index.intPart) cell.setAttribute("intpart", index.intPart);
            if (index.fracPart) cell.setAttribute("fracpart", index.fracPart);
          }
        });


        delete this.pane._cells[id];
        var n = document.createElement("div");
        n.appendChild(cell);

        var top = parus.parus8.styleSize(cell.style.top) - params.dy;
        var left = parus.parus8.styleSize(cell.style.left) - params.dx;

        cell.removeAttribute("style");
        cell.removeAttribute("uid");

        var cellObj = {
          top: top,
          left: left,
          trow: j - params.row + params.rowoffset,
          tcol: i - params.col + params.coloffset,
          tid: this.table.rn,
          cid: cell.getAttribute("cid"),
          fixed: !(cell.getAttribute("fo") == null),
          HTML: n.innerHTML.slice(4),
          ccnt: cell.getAttribute("ccnt"),
          rcnt: cell.getAttribute("rcnt"),
          innerHTML: cell.innerHTML,
          className: cell.getAttribute("class"),
          readOnly: ( !! cell.getAttribute("ro")),
          wordWrap: ( !! cell.getAttribute("wt"))
        };

        this.cells.byID[cell.getAttribute("cid")] = cellObj;

        this.cells.push(cellObj);
      };

      var formula = this.pane.formulas[id];
      if (formula) {
        this.table.formulas[id] = formula;
        //        delete this.pane.formulas[id];
      }

      var dependency = nativeDependencies[id];
      if (dependency) {
        this.table.dependencies[id] = dependency;
        //        delete this.pane.dependencies[id];
      }

      var formatCondition = this.pane.formatConditions[id];
      if (formatCondition) {
        this.table.formatConditions[id] = formatCondition;
        //        delete this.pane.formatConditions[id];
      }

      for (var dep in this.pane.dependencies) {
        dojo.forEach(this.pane.dependencies[dep], dojo.hitch(this, function(depid, idx) {
          if (id == depid) this.pane.dependencies[dep][idx] = this.table.rn;
        }));
      }
    }
  },

  loadTables: function(tablesInfo, tableValues) {
    if (tablesInfo["ROWSET"]) dojo.forEach(tablesInfo["ROWSET"][0]["ROW"], dojo.hitch(this, function(tableinfo) {

      var table = {
        rn: tableinfo["RN"][0]["#text"],
        info: tableinfo,
        pane: this,
        size: 0,
        cellsize: 0,
        commonCounter: 0,
        offsetSize: 0,
        col: dojo.number.parse(tableinfo["COL"][0]["#text"]),
        row: dojo.number.parse(tableinfo["ROWN"][0]["#text"]),
        width: dojo.number.parse(tableinfo["COL_CNT"][0]["#text"]),
        height: dojo.number.parse(tableinfo["ROWN_CNT"][0]["#text"]),
        readOnly: true,
        formulas: {},
        formatConditions: {},
        dependencies: {
          "*": dojo.clone(this.dependencies["*"])
        },
        cells: [],
        indexes: [],
        clones: [],
        totals: []
      };

      for (var i = 0; i < table.width; i++)
      for (var j = 0; j < table.height; j++)
      dojo.query("[cid=R" + (table.row + j) + "C" + (table.col + i) + "]", this.templateNode).forEach(function(cell) {
        if (!cell.getAttribute("ro")) table.readOnly = false;
      });

      dojo.mixin(table.totals, {
        byKey: {},
        byTotalKey: {}
      });
      dojo.mixin(table.clones, {
        byKey: {}
      });
      dojo.mixin(table.indexes, {
        byKey: {}
      });
      dojo.mixin(table.cells, {
        byID: {}
      });


      if (table.info["XMLINDEXES"][0]["ROWSET"]) dojo.forEach(tableinfo["XMLINDEXES"][0]["ROWSET"][0]["ROW"], dojo.hitch(this, function(indexinfo) {

        var dicts = indexinfo["XMLDICTS"] || null;
        if (dicts) {
          dicts = dojo.map(dicts[0]["ROWSET"][0]["ROW"], function(row) {
            return row["DICT"][0]["#text"];
          });
        };

        var indexInfo = {
          rn: indexinfo["RN"][0]["#text"],
          col: dojo.number.parse(indexinfo["COL"][0]["#text"]) - ((this.direction == "0") ? 1 : table.col),
          row: dojo.number.parse(indexinfo["ROWN"][0]["#text"]) - ((this.direction == "0") ? table.row : 1),
          dataType: dojo.number.parse(indexinfo["BITYPE"][0]["#text"]),
          strLen: null,
          intPart: null,
          fracPart: null,
          dictionary: null,
          minVal: null,
          maxVal: null,
          trim: null,
          value: null,
          dicts: dojo.clone(dicts)
        };
        if (indexinfo["STRLEN"]) indexInfo.strLen = dojo.number.parse(indexinfo["STRLEN"][0]["#text"]);
        if (indexinfo["INTPART"]) indexInfo.intPart = dojo.number.parse(indexinfo["INTPART"][0]["#text"]);
        if (indexinfo["FRACPART"]) indexInfo.fracPart = dojo.number.parse(indexinfo["FRACPART"][0]["#text"]);
        if (indexinfo["DICTIONARY"]) {
          indexInfo.dictionary = indexinfo["DICTIONARY"][0]["#text"];
          if (indexInfo.dictionary && parus.parus8.extraDictionaries._canCacheExtraDictionaries) parus.parus8.extraDictionaries.getStore(indexInfo.dictionary, this.agent, this.section);
        }

        if (indexinfo["NULLABLE"]) indexInfo.nullable = indexinfo["NULLABLE"][0]["#text"] == "1";
        if (indexinfo["DICT_CHECK"]) indexInfo.dictCheck = indexinfo["DICT_CHECK"][0]["#text"] == "1";
        if (indexinfo["DICT_VAL_NOTE"]) indexInfo.dictNote = indexinfo["DICT_VAL_NOTE"][0]["#text"] == "1";

        if (indexinfo["PATTERN"]) indexInfo.regExp = indexinfo["PATTERN"][0]["#text"];

        if (indexinfo["VALUE"]) {
          indexInfo.value = indexinfo["VALUE"][0]["#text"];
          if (indexInfo.dataType == "1" && indexInfo.value) {
            var s = indexInfo.value;
            s = s.split(".").join(",");
            indexInfo.value = dojo.number.parse(s);
          }
        }
        if (indexinfo["MINVAL"]) indexInfo.minVal = indexinfo["MINVAL"][0]["#text"];
        if (indexinfo["MAXVAL"]) indexInfo.maxVal = indexinfo["MAXVAL"][0]["#text"];
        if (indexinfo["TRIMSTRVAL"]) indexInfo.trim = dojo.number.parse(indexinfo["TRIMSTRVAL"][0]["#text"]);

        table.indexes.push(indexInfo);
        table.indexes.byKey[indexInfo.rn] = indexInfo;
      }));

      dojo.mixin(table, {
        table: table,
        placeClone: dojo.hitch(table, this.__clone)
      });

      var coords = this.cellCoords(table.col, table.row, table.col + table.width - 1, table.row + table.height - 1);

      table.size = (this.direction == "0") ? coords.h : coords.w;
      table.cellsize = (this.direction == "0") ? table.height : table.width;

      this._tables.push(table);
      this._tables.byKey[table.rn] = table;

    }));

    var affected = 1;

    if (this.direction == "0") {
      if (this.fixedRows) {
        affected = this.fixedRows + 1;
        this.splitPart(1, 1, this.cols, this.fixedRows);
        this._parts[0].node.style.zIndex = "20";
      };

      dojo.forEach(this._tables, dojo.hitch(this, function(table) {
        if (table.row > affected) this.splitPart(1, affected, this.cols, table.row - affected);
        dojo.mixin(table, {
          part: this.splitPart(1, table.row, this.cols, table.height)
        });

        table.part.table = table;

        affected = table.row + table.height;
      }));
      this.splitPart(1, affected, this.cols, this.rows - affected + 1);

      if (this.fixedCols) for (var r = 1; r <= this.rows; r++) for (var c = 1; c <= this.fixedCols; c++) {
        var cell = this._cells["R" + r + "C" + c];
        if (cell) {
          cell.setAttribute("fo", parus.parus8.styleSize(cell.style.left));
          cell.style.zIndex = "10";
        }
      }

    }
    else {

      if (this.fixedCols) {
        affected = this.fixedCols + 1;
        this.splitPart(1, 1, this.fixedCols, this.rows);
        this._parts[0].node.style.zIndex = "20";
      };

      dojo.forEach(this._tables, dojo.hitch(this, function(table) {

        if (table.col > affected) this.splitPart(affected, 1, table.col - affected, this.rows);

        dojo.mixin(table, {
          part: this.splitPart(table.col, 1, table.width, this.rows)
        });

        table.part.table = table;

        affected = table.col + table.width;
      }));

      this.splitPart(affected, 1, this.cols - affected + 1, this.rows);


      if (this.fixedRows) for (var r = 1; r <= this.fixedRows; r++) for (var c = 1; c <= this.cols; c++) {
        var cell = this._cells["R" + r + "C" + c];
        if (cell) {
          cell.setAttribute("fo", parus.parus8.styleSize(cell.style.top));
          cell.style.zIndex = "10";
        }
      }
    };

    dojo.forEach(this._tables, dojo.hitch(this, function(table) {

      var tableMap = [];

      if (this.direction == "0") for (var i = 0; i < table.height; i++) tableMap.push(0)
      else for (var i = 0; i < table.width; i++) tableMap.push(0);

      if (table.info["XMLTOTALS"][0]["ROWSET"]) dojo.forEach(table.info["XMLTOTALS"][0]["ROWSET"][0]["ROW"],

      dojo.hitch(this, function(totalinfo) {
        var col = dojo.number.parse(totalinfo["COL"][0]["#text"]);
        var row = dojo.number.parse(totalinfo["ROWN"][0]["#text"]);
        var width = dojo.number.parse(totalinfo["COL_CNT"][0]["#text"]);
        var height = dojo.number.parse(totalinfo["ROWN_CNT"][0]["#text"]);

        if (this.direction == "0") {
          for (var i = row - table.row; i < row - table.row + height; i++) {
            tableMap[i] = totalinfo["RN"][0]["#text"];
          }
        }
        else {
          for (var i = col - table.col; i < col - table.col + width; i++)
          tableMap[i] = totalinfo["RN"][0]["#text"];
        }
      }));

      var cellsoffset = 0;
      for (var i = 0; i < tableMap.length; i++)
      if (!tableMap[i]) {
        cellsoffset = i;
        break;
      }

      if (table.info["XMLTOTALS"][0]["ROWSET"]) dojo.forEach(table.info["XMLTOTALS"][0]["ROWSET"][0]["ROW"], dojo.hitch(this, function(totalinfo) {
        var total = {
          rn: totalinfo["RN"][0]["#text"],
          totalkey: totalinfo["TOTALKEY"][0]["#text"],
          pane: this,
          table: table,
          size: 0,
          cellsize: 0,
          location: totalinfo["LOCATION"][0]["#text"],
          level: parseInt(totalinfo["LVL"][0]["#text"]),
          col: dojo.number.parse(totalinfo["COL"][0]["#text"]),
          row: dojo.number.parse(totalinfo["ROWN"][0]["#text"]),
          width: dojo.number.parse(totalinfo["COL_CNT"][0]["#text"]),
          height: dojo.number.parse(totalinfo["ROWN_CNT"][0]["#text"]),
          cells: [],
          clones: [],
          indexes: table.indexes
        };

        dojo.mixin(total.clones, {
          byKey: {}
        });

        dojo.mixin(total.cells, {
          byID: {}
        });

        dojo.mixin(total, {
          placeClone: dojo.hitch(total, this.__clone)
        });

        var coords = this.cellCoords(total.col, total.row, total.col + total.width - 1, total.row + total.height - 1);

        total.size = (this.direction == "0") ? coords.h : coords.w;
        total.cellsize = (this.direction == "0") ? total.height : total.width;

        table.size -= total.size;
        table.cellsize -= total.cellsize;

        dojo.hitch(total, this.__createTemplate)(0, cellsoffset);

        table.totals.push(total);
        table.totals.byKey[total.rn] = total;
        table.totals.byTotalKey[total.totalkey] = total;

        if (this._maxTotalLevel == null) this._maxTotalLevel = total.level;
        if (this._minTotalLevel == null) this._minTotalLevel = total.level;

        if (this._maxTotalLevel < total.level) this._maxTotalLevel = total.level;
        if (this._minTotalLevel > total.level) this._minTotalLevel = total.level;
      }));

      var offset = 0;

      for (var i = 0; i < tableMap.length; i++) {
        if (tableMap[i]) {
          if ((table.totals.byKey[tableMap[i]].row - table.row) == i) offset += table.totals.byKey[tableMap[i]].size;
        }
        else break;
      };

      dojo.hitch(table, this.__createTemplate)(offset, 0);

      var dy = (this.direction == "0") ? parus.parus8.styleSize(table.part.node.style.height) : 0;
      var dx = (this.direction == "0") ? 0 : parus.parus8.styleSize(table.part.node.style.width);

      for (var i = table.part.index + 1; i < this._parts.length; i++) {
        dojo.style(this._parts[i].node, {
          top: (parus.parus8.styleSize(this._parts[i].node.style.top) - dy) + "px",
          left: (parus.parus8.styleSize(this._parts[i].node.style.left) - dx) + "px"
        });
      }

      dojo.style(table.part.node, {
        width: ((this.direction == "0") ? parus.parus8.styleSize(table.part.node.style.width) : 0) + "px",
        height: ((this.direction == "0") ? 0 : parus.parus8.styleSize(table.part.node.style.height)) + "px"
      });

      dojo.style(this.templateNode, {
        height: (parus.parus8.styleSize(this.templateNode.style.height) - dy) + "px",
        width: (parus.parus8.styleSize(this.templateNode.style.width) - dx) + "px"
      });


      if (this.gutterNode) dojo.style(this.gutterNode, {
        height: (parus.parus8.styleSize(this.gutterNode.style.height) - dy) + "px",
        width: (parus.parus8.styleSize(this.gutterNode.style.width) - dx) + "px"
      });

    }));


    dojo.forEach(this._parts, dojo.hitch(this, function(part) {
      if (part.table) {
        part.node.parentNode.removeChild(part.node);
        if (this.direction == "0") part.node.style.height = "0px";
        else part.node.style.width = "0px";
      }
    }));

    if (parus.balance.showTemplateGutter) if ( !! this._maxTotalLevel || !! this._minTotalLevel) this.gutterSize = ((this._maxTotalLevel || 0) + 1) * 20;


    var oldKey = "";
    var clone;
    var clones = [];

    dojo.forEach(tableValues, dojo.hitch(this, function(value) {

      var tableRN = value["RN"];
      var cloneRN = dojo.number.parse(value["NUMB"]);
      var totalRN = value["TOTAL"];
      var indexRN = value["INDEXRN"];

      var table = this._tables.byKey[tableRN];

      if (!table) return;

      var total = (totalRN) ? table.totals.byKey[totalRN] : table;

      if (!total) return;

      if (clone && ((tableRN + "." + cloneRN) != oldKey)) this.checkCloneHeight(clone);

      oldKey = tableRN + "." + cloneRN

      clone = total.clones.byKey[cloneRN];

      if (!clone) {
        clone = total.placeClone(cloneRN);
        clones.push(clone);
      }

      var index = table.indexes.byKey[indexRN];

      if (!index) return;

      var cell = clone.cells.byKey["R" + index.row + "C" + index.col];

      if (!cell) return;

      var v = parus.parus8.externalStringToValue(value["VALUE"], index.dataType);
      if ((v !== "") & (v !== null)) this.setCellText(cell, null, v)

    }));

    if (clone) this.checkCloneHeight(clone);

    dojo.forEach(clones, function(clone, idx) {
      var children = [];
      var level = clone.owner.level;
      var trn = clone.table.rn;

      if (level) {
        if (clone.owner.location == "1") for (var i = idx + 1; i < clones.length; i++) {
          if (clones[i].table.rn != trn) break;
          if ((clones[i].owner.level || 1000) > level) {
            if (!clones[i].treeParents) clones[i].treeParents = [];
            clones[i].treeParents.push(clone);
            children.push(clones[i]);
          }
          else break;
        }
        else for (var i = idx - 1; i >= 0; i--) {
          if (clones[i].table.rn != trn) break;
          if ((clones[i].owner.level || 1000) > level) {
            if (!clones[i].treeParents) clones[i].treeParents = [];
            clones[i].treeParents.push(clone);
            children.push(clones[i]);
          }
          else break;
        }
      };

      dojo.mixin(clone, {
        treeChildren: children
      });

    });

    dojo.forEach(clones, function(clone) {
      if (clone.treeParents) clone.treeParents.sort(function(a, b) {
        return (b.owner.level || 1000) - (a.owner.level || 1000);
      });

      if (clone.treeChildren) clone.treeChildren.sort(function(a, b) {
        return (a.owner.level || 1000) - (b.owner.level || 1000);
      });

    });

    dojo.forEach(this._parts, dojo.hitch(this, function(part) {
      this.templateNode.appendChild(part.node);
      if (part.table) this.shiftParts(part, part.table.offsetSize, true);
    }));

    dojo.forEach(this._tables, function(table) {
      if (table.clones.length == 0) table.placeClone(null, true);
    });

    dojo.forEach(this._tables, function(table) {
      dojo.forEach(table.clones, function(clone) {
        clone.calcAll();
      });
      dojo.forEach(table.totals, function(total) {
        dojo.forEach(total.clones, function(clone) {
          clone.calcAll();
        });
      });
    });
  },

  checkCloneHeight: function(clone) {
    dojo.forEach(clone.cells, dojo.hitch(this, function(cell) {
      this.checkCellHeight(cell, null, true, clone, false);
    }));
    this.drawAllCanvas();
  },

  loadNewData: function(newDataArray, newRemarksArray) {

    this._allValuesLoaded = false;

    var indexes = [];
    var tables = [];
    dojo.forEach(newDataArray, function(node) {
      if (node.nodeName == "INDEXES") indexes = node;
      else if (node.nodeName == "TABLES") tables = node;
    });

    if (indexes) {

      this.progressIndicate("Загружаются новые значения показателей....");

      var nodes = parus.parus8.rowNodes(indexes);

      dojo.forEach(nodes, dojo.hitch(this, function(index) {
        var id = index.getAttribute("ID");
        var v = index.getAttribute("VALUE");
        var staticValue = this._staticValues.byKey[id];
        if (staticValue) {
          this.setCellText(staticValue.node, staticValue.valueNode, parus.parus8.externalStringToValue(v, staticValue.dataType));
        }
      }));

    }

    this._remarksStore = new parus.gridData({
      persistent: true,
      _data: []
    });

    if (tables) {

      this.progressIndicate("Подготавливаются таблицы показателей....");

      dojo.forEach(this._parts, dojo.hitch(this, function(part) {
        this.templateNode.appendChild(part.node);
        if (part.table) this.shiftParts(part, -part.table.offsetSize, true);
      }));


      var nodes = parus.parus8.rowNodes(tables);

      var clones = [];

      dojo.forEach(nodes, dojo.hitch(this, function(tableNode, idx) {

        this.progressIndicate("Загружается таблица показателей номер " + (idx + 1) + " из " + nodes.length + "....");

        var id = tableNode.getAttribute("ID");
        var table = this._tables.byKey[id];
        if (!table) return;

        dojo.forEach(table.clones, dojo.hitch(this, function(clone) {
          if (clone.gutterTreeNode) clone.gutterTreeNode.destroyRecursive();
          clone.node.parentNode.removeChild(clone.node);
        }));


        dojo.forEach(table.totals, dojo.hitch(this, function(total) {
          dojo.forEach(total.clones, dojo.hitch(this, function(clone) {
            if (clone.gutterTreeNode) clone.gutterTreeNode.destroyRecursive();
            clone.node.parentNode.removeChild(clone.node);
          }));

          total.clones = [];
          dojo.mixin(total.clones, {
            byKey: {}
          });

        }));

        dojo.mixin(table, {
          clones: [],
          commonCounter: 0,
          offsetSize: 0
        });

        dojo.mixin(table.clones, {
          byKey: {}
        });

        var rows = parus.parus8.rowNodes(tableNode);
        dojo.forEach(rows, dojo.hitch(this, function(rowNode) {
          var id = rowNode.getAttribute("NUMB") || 1;

          if (id == 1) return;

          var totalid = rowNode.getAttribute("TOTAL") || "";
          var clone;

          if (totalid) {
            var total = table.totals.byTotalKey[totalid];
            if (!total) return;

            clone = total.placeClone(id);

          }
          else clone = table.placeClone(id);

          clones.push(clone);

          var values = parus.parus8.rowNodes(rowNode);

          var maxNumb = 0;

          dojo.forEach(values, dojo.hitch(this, function(value) {
            if (value.nodeName == "INDEX") {

              var indexRN = value.getAttribute("ID");

              var index = table.indexes.byKey[indexRN];

              if (!index) return;

              var cell = clone.cells.byKey["R" + index.row + "C" + index.col];

              if (!cell) return;

              var staticValue = clone._staticValues.byKey[indexRN];

              if (!staticValue) return;

              var v = parus.parus8.externalStringToValue(value.getAttribute("VALUE"), index.dataType);
              if ((v !== "") & (v !== null)) this.setCellText(cell, staticValue.valueNode, v)
            }
          }));
          this.checkCloneHeight(clone);


        }));
      }));


      dojo.forEach(clones, function(clone, idx) {
        var children = [];
        var level = clone.owner.level;
        var trn = clone.table.rn;


        if (level) {
          if (clone.owner.location == "1") for (var i = idx + 1; i < clones.length; i++) {
            if (clones[i].table.rn != trn) break;
            if ((clones[i].owner.level || 1000) > level) {
              if (!clones[i].treeParents) clones[i].treeParents = [];
              clones[i].treeParents.push(clone);
              children.push(clones[i]);
            }
            else break;
          }
          else for (var i = idx - 1; i >= 0; i--) {
            if (clones[i].table.rn != trn) break;
            if ((clones[i].owner.level || 1000) > level) {
              if (!clones[i].treeParents) clones[i].treeParents = [];
              clones[i].treeParents.push(clone);
              children.push(clones[i]);
            }
            else break;
          }
        };

        dojo.mixin(clone, {
          treeChildren: children
        });
      });

      dojo.forEach(clones, function(clone) {
        if (clone.treeParents) clone.treeParents.sort(function(a, b) {
          return (b.owner.level || 1000) - (a.owner.level || 1000);
        });

        if (clone.treeChildren) clone.treeChildren.sort(function(a, b) {
          return (a.owner.level || 1000) - (b.owner.level || 1000);
        });

      });


      if (this.gutterNode) {
        setTimeout(dojo.hitch(this, this.buildGutterTree), 100);
      };


      this.progressIndicate();
      this._allValuesLoaded = true;
    }

    dojo.forEach(newRemarksArray, dojo.hitch(this, function(remarkInfo) {

      var INDEXRN = parus.parus8.nodeField(remarkInfo, "INDEXRN");
      var CLONERN = parus.parus8.nodeField(remarkInfo, "CLONERN");
      var TABLERN = parus.parus8.nodeField(remarkInfo, "TABLERN");
      var NUMB = parus.parus8.nodeField(remarkInfo, "NUMB");

      var found = false;
      dojo.forEach(this._remarksStore._data, function(item) {

        if ((item.INDEXRN == INDEXRN) && (item.CLONERN == CLONERN) && (item.TABLERN == TABLERN) && (item.NUMB == NUMB)) {
          found = true;
          dojo.mixin(item, {
            CHANGE_DATE: parus.parus8.nodeField(remarkInfo, "CHANGE_DATE"),
            CODE: parus.parus8.nodeField(remarkInfo, "CODE"),
            NAME: parus.parus8.nodeField(remarkInfo, "NAME"),
            NOTE: parus.parus8.nodeField(remarkInfo, "NOTE"),
            _NEW: true
          });
        }
      });

      if (!found) {
        var params = {
          COLOR: parus.parus8.nodeField(remarkInfo, "COLOR"),
          INDEXRN: INDEXRN,
          CLONERN: CLONERN,
          TABLERN: TABLERN,
          CHANGE_DATE: parus.parus8.nodeField(remarkInfo, "CHANGE_DATE"),
          CODE: parus.parus8.nodeField(remarkInfo, "CODE"),
          NAME: parus.parus8.nodeField(remarkInfo, "NAME"),
          NOTE: parus.parus8.nodeField(remarkInfo, "NOTE"),
          NUMB: NUMB,
          _NEW: true
        };

        this._remarksStore.add(params);
        this.applyRemarkColor(params);
      }

    }));

    dojo.forEach(this._parts, dojo.hitch(this, function(part) {
      this.templateNode.appendChild(part.node);
      if (part.table) this.shiftParts(part, part.table.offsetSize, true);
    }));

    dojo.forEach(this._tables, function(table) {
      if (table.clones.length == 0) table.placeClone(null, true);
    });


    this.__fireDefferedAttrs();



  },

  _setTitleAttr: function(value) {
    this.inherited(arguments);
    if (this.autonomousMode) document.title = value;
    dojo.place("<span>" + value + "<span>", this.headingContentPane.containerNode.firstChild, "only");
    this.title = value;
    this.onTitleChanged();
  },

  __makeFormula: function(oldformula, dx, dy) {
    return function() {
      return oldformula.call(this, dx, dy);
    }
  },

  __parseCellId: function(id) {

    var id = (/^R(\d+)C(\d+)$/g).exec(id);
    return {
      row: Number(id[1]),
      col: Number(id[2])
    };
  }

});


dojo.mixin(parus.templateGridPane, {

  remarkToTop: function(node) {
    dojo.query("[rid='h']", node.parentNode).style({
      zIndex: 50
    });
    dojo.style(node, {
      zIndex: 55
    });
  },

  followLogMessage: function(paneId, balanceIndex, tableRN, cloneRN, staticRN) {
    var pane = dijit.byId(paneId);
    if (!pane) return;

    if (tableRN) {

      var table = pane._tables.byKey[tableRN];
      if (!table) return;

      if (table.gutterTreeNode) table.gutterTreeNode.attr("expanded", true);

      var clone = table.clones.byKey[cloneRN];

      if (!clone) dojo.forEach(table.totals, function(total) {
        if (!clone) clone = total.clones.byKey[cloneRN];
      });

      if (!clone) {
        pane.followCell(table.clones[0].cells[0]);
        pane.selectCell(table.clones[table.clones.length - 1].cells[table.clones[table.clones.length - 1].cells.length - 1], true);
        return;
      }

      if (clone.treeParents) dojo.forEach(clone.treeParents, function(clone) {
        if (clone.gutterTreeNode) clone.gutterTreeNode.attr("expanded", true);
      });

      var staticValue = clone._staticValues.byKey[staticRN];
      if (!staticValue) {
        pane.followCell(clone.cells[0]);
        pane.selectCell(clone.cells[clone.cells.length - 1], true);
        return;
      };
      if (!staticValue.node) {
        pane.followCell(clone.cells[0]);
        pane.selectCell(clone.cells[clone.cells.length - 1], true);
        return;
      };

      pane.followCell(staticValue.node);

    }
    else {
      var staticValue = pane._staticValues.byKey[balanceIndex];

      if (staticValue) if (staticValue.node) pane.followCell(staticValue.node);
    }
  },

  formatLogMessage: function(data, rowIndex, column) {

    return ("<a href=\"javascript:parus.templateGridPane.followLogMessage(" + "'" + column.grid.templatePane.id + "'," + "'" + (column.grid.store.getValue(column.grid.getItem(rowIndex), "BALANCEINDEX") || "") + "'," + "'" + (column.grid.store.getValue(column.grid.getItem(rowIndex), "TABLE_RN") || "") + "'," + "'" + (column.grid.store.getValue(column.grid.getItem(rowIndex), "ROW_NUMB") || "") + "'," + "'" + (column.grid.store.getValue(column.grid.getItem(rowIndex), "BLTABLESIND") || "") + "'" + ")\">" + data + "</a>");

  }
});

dojo.mixin(parus.parus8, {

  _internalClipboard: null

});

if (!parus) parus = {};

if (!parus.report) dojo.mixin(parus, {
  report: {}
});

dojo.mixin(parus.report, {

  startup: function() {

    parus.balance.availableUnits = dojo.map(parus.parus8.rowNodes(parus.database.query("availableUnits")), function(node) {
      return parus.parus8.nodeField(node, "UNITCODE")
    });

    if (dojo.indexOf(parus.balance.availableUnits, "BalanceReports") == -1) {
      parus.parus8.errorMessage("У вас нет доступа к разделу <br/> \"Первичные/сводные отчеты\"<br/> в приложении <br/> \"Сведение отчетности - Центр учета Online\". <br/>Обратитесь к администратору.", parus.parus8.logout);
      return;
    };

    var params = null;

    dojo.xhrGet({

      url: "../.system/session.xml",
      handleAs: "xml",
      sync: true,
      preventCache: true,

      load: function(response) {

        if (!dojo.isIE) response.normalize();

        var LNodes = response.documentElement.getElementsByTagName("*");

        for (var i = 0; i != LNodes.length; i++) {
          if (LNodes[i].nodeName == "params") params = LNodes[i].childNodes.item(0).nodeValue;
        }

        return (response);

      }
    });

    params = parus.parus8.hexDecodeParams(params);


    var doit = function(template) {

      parus.parus8.extraDictionaries._canCacheExtraDictionaries = (parus.parus8.optionValue("BalanceOnlineCacheContractorDictValues") != "0");
      parus.parus8.extraDictionaries._autoCompleteLimit = parus.parus8.optionValue("BalanceOnlineAutoCompleteDictSize");
      parus.dictionaries._autoCompleteLimit = parus.parus8.optionValue("BalanceOnlineAutoCompleteUnitSize");

      var settings = parus.userdata.get("parus.balance.primaryMasterGrid");

      if (settings) if (settings.additions) parus.balance.showTemplateGutter = settings.additions.showGutter;

      var container;

      var contentPane = parus.balance.showReportValues(params[0], params[1], null, null, null, null, template, null, null, null, function() {
        dojo.fadeIn({
          node: container.domNode,
          duration: 300
        }).play();
      });

      loadingDiv.style.display = "none";

      container = new dijit.layout.BorderContainer({
        design: "headline",
        gutters: false,
        "class": "balanceTemplateContentPane",
        style: "height:100%;width:100%;padding:0;opacity:0;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"
      }, dojo.place("<div></div>", dojo.body(), "last"))

      var pane = contentPane.getChildren()[0].getChildren()[1];

      dojo.mixin(pane, {
        autonomousMode: true,
        onModified: function() {

          var list = dojo.query("*", pane.headingContentPane.containerNode);
          list.removeClass("balanceReadOnlyHeader");
          list.removeClass("balanceModifiedHeader");
          if (pane.readonly) list.addClass("balanceReadOnlyHeader");
          else if (pane.modified) list.addClass("balanceModifiedHeader");

          if (parus.parus8._embeddedMode) {
            parus.embeddedMode.changeTabState(pane.modified);
          }
        }
      });

      if (parus.parus8._embeddedMode) {
        parus.embeddedMode.registerOnCloseCallback(dojo.hitch(pane, function(tabId) {
          this.onClose();
        }));

        parus.embeddedMode.registerOnShowCallback(function() {
          container.resize();
        });

      }

      container.addChild(contentPane);
      container.startup();

    };


    parus.database.query("BalanceReportTemplates", {
      "REPORT": params[0]
    }, dojo.hitch(this, function(response) {

      var templates = parus.parus8.rowNodes(response);
      if (templates.length == 0) {
        parus.parus8.errorMessage("Трафареты для редактирования значений отсутствуют или недоступны.");
        return;
      };

      var template;
      var direction;


      if (templates.length == 1) {
        template = parus.parus8.nodeField(templates[0], "RN");
        direction = parus.parus8.nodeField(templates[0], "DIRECT_TABLE");
      }
      else dojo.forEach(templates, function(templateNode) {
        if ((parus.parus8.nodeField(templateNode, "RN") == params[2]) || (!template && parus.parus8.nodeField(templateNode, "EDIT_DEFAULT") == "1")) {
          template = parus.parus8.nodeField(templateNode, "RN");
          direction = parus.parus8.nodeField(templateNode, "DIRECT_TABLE");
        }
      });


      if (template) doit(template)
      else {

        var dialog = new parus.balanceTemplatesDialog({

          templates: templates,

          onShow: function() {
            dialog.CancelButton.domNode.style.display = "none";
            dialog.dialog.closeButtonNode.style.display = "none";
          },

          onApply: dojo.hitch(this, function() {

            dojo.forEach(dialog.templatesGrid.selection.getSelected(), function(item) {
              template = dialog.templatesGrid.store.getValue(item, "RN", "");
              direction = dialog.templatesGrid.store.getValue(item, "DIRECT_TABLE", "")
            });

            if (!template) return false;

            doit(template)

            return true;
          })

        });
        dialog.show();
      }

    }));

  }

});

dojo.mixin(parus.parus8, {

  consComparationData: null,

  showIndexConsComparationItems: function(args) {
    var dialog = new parus.balanceIndexConsComparationItems(args || {});
    dialog.show();
  },

  performIndexConsComparation: function(args) {

    var dialog = new parus.balanceIndexConsComparation(args || {});
    dialog.show();

  },

  addIndexConsComparationTemplate: function(template) {

    parus.parus8.consComparationData = parus.parus8.consComparationData || {
      dataType: template.dataType,
      intPart: template.intPart,
      fracPart: template.fracPart,
      result: template.result,
      items: []
    };

    parus.parus8.consComparationData.intPart =
    Math.max(parus.parus8.consComparationData.intPart || 0, template.intPart || 0);

    parus.parus8.consComparationData.fracPart =
    Math.max(parus.parus8.consComparationData.fracPart || 0, template.fracPart || 0);

    var idents = {};

    var N;

    dojo.forEach(template.items, function(item) {

      if (item["DATA"]) {
        item.dataInfo = parus.parus8.rowNodes(parus.database.execute("IndexConsDataID", {
          "DATA": item["DATA"]
        }))[0];
      }

      var ident = item["IDENTIFIER"];
      if (parus.parus8.consComparationData.items.length && ident) {

        var found = -1;

        if (item.dataInfo) {
          var key = (parus.parus8.nodeField(item.dataInfo, "INDEX") + "-" + (parus.parus8.nodeField(item.dataInfo, "REPORT") || "") + "-" + (parus.parus8.nodeField(item.dataInfo, "SUBREPORT") || "") + "-" + (parus.parus8.nodeField(item.dataInfo, "INDEX") || "") + "-" + (parus.parus8.nodeField(item.dataInfo, "TABLE") || "") + "-" + (parus.parus8.nodeField(item.dataInfo, "ROWID") || ""));
          dojo.forEach(parus.parus8.consComparationData.items, function(item, idx) {
            if (item["ID"] == key) found = idx;
          });
        };

        if (found != -1) {
          ident = parus.parus8.consComparationData.items[found]["IDENTIFIER"];
        }
        else {
          if (!N) N = parus.balanceIndexConsComparation.templateApplyIndex();
          var match = ident.match(/^Шаблон(\d+)_.*$/);
          if (!match) ident = "Шаблон" + N + "_" + ident;
          else ident = ident.split(match[1]).join(N);
        }
      };
      idents[item["IDENTIFIER"]] = ident;
    });

    var D = new Date().valueOf();

    dojo.forEach(template.items, function(item, idx) {

      if (item["DATA"]) {
        var ID = item.dataInfo;

        if (!ID) return;

        var info = parus.parus8.rowNodes(parus.database.execute("IndexConsInfo", {
          "REPORT": parus.parus8.nodeField(ID, "REPORT"),
          "SUBREPORT": parus.parus8.nodeField(ID, "SUBREPORT"),
          "INDEX": parus.parus8.nodeField(ID, "INDEX"),
          "TABLE": parus.parus8.nodeField(ID, "TABLE"),
          "ROWID": parus.parus8.nodeField(ID, "ROWID")
        }))[0];

        if (!info) return;

        parus.parus8.consComparationData.intPart =
        Math.max(parus.parus8.consComparationData.intPart || 0, parus.parus8.nodeField(info, "INTPART") || 0);
        parus.parus8.consComparationData.fracPart =
        Math.max(parus.parus8.consComparationData.fracPart || 0, parus.parus8.nodeField(info, "FRACPART") || 0);

        if (parus.parus8.consComparationData.dataType != parus.parus8.nodeField(info, "DATATYPE")) {
          parus.parus8.errorMessage("Тип показателя не соответствует уже добавленным к сравнению показателям.");
          return;
        };

        if (parus.parus8.consComparationData.result != parus.parus8.nodeField(info, "RESULT")) {
          parus.parus8.errorMessage("Тип состава показателя не соответствует уже добавленным к сравнению показателям.");
          return;
        };

        parus.parus8.addIndexConsComparationItem({
          "REPORT": parus.parus8.nodeField(ID, "REPORT"),
          "SUBREPORT": parus.parus8.nodeField(ID, "SUBREPORT"),
          "INDEX": parus.parus8.nodeField(ID, "INDEX"),
          "TABLE": parus.parus8.nodeField(ID, "TABLE"),
          "ROWID": parus.parus8.nodeField(ID, "ROWID"),
          "TITLE": parus.parus8.nodeField(info, "TITLE"),
          "INCLUDEDIFF": item["INCLUDEDIFF"],
          "IDENTIFIER": idents[item["IDENTIFIER"]]
        });
      }
      else {
        expression = item["EXPRESSION"];

        for (var id in idents) {
          expression = expression.split(id).join(idents[id]);
        }

        parus.parus8.addIndexConsComparationItem({
          "ID": D - idx,
          "TITLE": item["TITLE"],
          "EXPRESSION": expression,
          "INCLUDEDIFF": item["INCLUDEDIFF"]
        });
      }
    });

  },

  addIndexConsComparationItem: function(obj) {

    if (!obj) return;

    var key = obj["ID"] || (obj["INDEX"] + "-" + (obj["REPORT"] || "") + "-" + (obj["SUBREPORT"] || "") + "-" + (obj["INDEX"] || "") + "-" + (obj["TABLE"] || "") + "-" + (obj["ROWID"] || ""));

    if (dojo.filter(parus.parus8.consComparationData.items, function(item) {
      return (item["ID"] == key);
    }).length) return;

    if (!obj["IDENTIFIER"] && !obj["EXPRESSION"]) {

      var identCode = 1;

      while (dojo.filter(parus.parus8.consComparationData.items, function(item) {
        return (item["IDENTIFIER"] == parus.parus8.toLetters(identCode));
      }).length)
      identCode++;

      dojo.mixin(obj, {
        "IDENTIFIER": parus.parus8.toLetters(identCode),
        "INCLUDEDIFF": true
      });
    }

    dojo.mixin(obj, {
      "ID": key
    });

    parus.parus8.consComparationData.items.push(obj);
    parus.parus8.consComparationDataModified();
  },

  consComparationDataModified: function() {
    if (parus.parus8._embeddedMode) {
      parus.embeddedMode.globalChanged("parus.parus8.consComparationData", parus.parus8.consComparationData || {});
      parus.embeddedMode.globalChanged("parus.balanceIndexConsComparation._templates", {});
    }
  }

});


dojo.declare("parus.templateGridPane.verticalGutterTreeNode", [dijit._Widget, dijit._Templated, dijit._CssStateMixin], {

  templateString: dojo.cache("parus", "verticalGutterTreeNode.html"),

  expanded: true,

  height: 0,

  top: 0,

  left: 0,

  pane: null,

  table: null,

  clone: null,

  attributeMap: dojo.delegate(dijit._WidgetBase, {
    expanded: ""
  }),

  _setExpandedAttr: function(value) {
    if (this.expanded != value) {
      this.expanded = value;
      this._perform();
    }
  },

  postCreate: function() {
    this.inherited(arguments);
    this._resize();
  },

  _resize: function() {
    dojo.style(this.domNode, {
      position: "absolute",
      width: "20px",
      height: this.height + "px",
      top: this.top + "px",
      left: this.left + "px"
    });
    this.treeNode.style.zIndex = 100;
  },


  _perform: function() {

    if (this.expanded) {
      dojo.removeClass(this.treeNode, "dijitTreeExpandoClosed");
      dojo.addClass(this.treeNode, "dijitTreeExpandoOpened");
      this.fillerNode.style.display = "";
      this.cornerNode.style.display = "";
      this.treeNode.style.zIndex = 100;

      if (this.clone) {

        var dh = 0;
        var t = 0;
        var location = this.clone.owner.location;

        dojo.forEach(this.clone.treeChildren, dojo.hitch(this, function(clone) {

          dh += clone.size;
          if (location == "0") t -= clone.size;

          this.pane.shiftClones(clone.table, clone.commonIndex, clone.size);
          clone.table.offsetSize = clone.table.offsetSize + clone.size;

          clone.node.style.height = clone.size + "px";

          if (clone.gutterTreeNode) {
            var visible = true;
            dojo.forEach(clone.treeParents, function(cln) {
              if (cln.gutterTreeNode) if (!cln.gutterTreeNode.expanded) visible = false;
            });

            clone.gutterTreeNode.domNode.style.display = visible ? "" : "none";
          }

        }));

        this.pane.shiftParts(this.clone.part, dh);

        this.height = dh + this.clone.size;
        this.top = t + parus.parus8.styleSize(this.clone.node.style.top) + parus.parus8.styleSize(this.clone.part.node.style.top);

      }
      else {

        dojo.forEach(this.table.totals, function(total) {
          dojo.forEach(total.clones, function(clone) {
            if (clone.gutterTreeNode) {
              var visible = true;
              dojo.forEach(clone.treeParents, function(cln) {
                if (cln.gutterTreeNode) if (!cln.gutterTreeNode.expanded) visible = false;
              });
              clone.gutterTreeNode.domNode.style.display = visible ? "" : "none";
            }
          });
        });


        this.pane.shiftParts(this.table.part, this.table.offsetSize);

        this.height = this.table.offsetSize;

      }
    }
    else {

      dojo.removeClass(this.treeNode, "dijitTreeExpandoOpened");
      dojo.addClass(this.treeNode, "dijitTreeExpandoClosed");
      this.fillerNode.style.display = "none";
      this.cornerNode.style.display = "none";
      this.treeNode.style.zIndex = 500;

      if (this.clone) {

        var dh = 0;
        dojo.forEach(this.clone.treeChildren, dojo.hitch(this, function(clone) {
          dh += clone.size;
          this.pane.shiftClones(clone.table, clone.commonIndex, -clone.size);
          clone.table.offsetSize = clone.table.offsetSize - clone.size;

          clone.node.style.height = "0px";
          if (clone.gutterTreeNode) {
            clone.gutterTreeNode.attr("expanded", true);
            clone.gutterTreeNode.domNode.style.display = "none";
          }
        }));


        this.pane.shiftParts(this.clone.part, -dh);

        this.height = this.clone.size;
        this.top = parus.parus8.styleSize(this.clone.node.style.top) + parus.parus8.styleSize(this.clone.part.node.style.top);


      }
      else {

        dojo.forEach(this.table.totals, function(total) {
          dojo.forEach(total.clones, function(clone) {
            if (clone.gutterTreeNode) {
              clone.gutterTreeNode.domNode.style.display = "none";
            }
          });
        });

        this.pane.shiftParts(this.table.part, -this.table.offsetSize);
        this.height = 18;
      }
    }
    this._resize();
  },

  _onTreeNodeClick: function() {
    parus.parus8.registerAction();
    this.expanded = !this.expanded;
    this._perform();
  }


});


dojo.declare("parus.templateGridPane.gutterTreeLevel", [dijit._Widget, dijit._Templated, dijit._CssStateMixin], {

  templateString: "<div class=\"gutterLevelIndex\" dojoAttachEvent=\"onclick:_onLevelClick\" ><span dojoAttachPoint=\"content\"></span></div>",

  level: 0,

  pane: null,

  postCreate: function() {
    this.inherited(arguments);
    this._render();
  },

  _render: function() {
    dojo.style(this.domNode, {
      left: (this.level * 20 - 3) + "px"
    });
    this.content.innerHTML = (this.level + 1);
  },

  _collapse: function() {
    if (this.level == 0) {
      dojo.forEach(this.pane._tables, function(table) {
        if (table.gutterTreeNode) table.gutterTreeNode.attr("expanded", false);
      })
    }
    else {
      dojo.forEach(this.pane._tables, dojo.hitch(this, function(table) {
        dojo.forEach(table.totals, dojo.hitch(this, function(total) {
          if (total.level == this.level) dojo.forEach(total.clones, dojo.hitch(this, function(clone) {
            if (clone.gutterTreeNode) clone.gutterTreeNode.attr("expanded", false)
          }));
        }));
      }));
    }
  },


  _expand: function() {
    if (this.level == 0) {
      dojo.forEach(this.pane._tables, function(table) {
        if (table.gutterTreeNode) table.gutterTreeNode.attr("expanded", true);
      })
    }
    else {
      dojo.forEach(this.pane._tables, dojo.hitch(this, function(table) {
        dojo.forEach(table.totals, dojo.hitch(this, function(total) {
          if (total.level == this.level) dojo.forEach(total.clones, dojo.hitch(this, function(clone) {
            if (clone.gutterTreeNode) clone.gutterTreeNode.attr("expanded", true)
          }));
        }));
      }));
    }
  },


  _onLevelClick: function() {

    parus.parus8.registerAction();

    var c = dojo.coords(this.pane.templateNode);
    var topNode = document.elementFromPoint(this.pane.templateNode.parentNode.scrollLeft + c.x + 2, this.pane.templateNode.parentNode.scrollTop + c.y + 2);

    var expanded = true;

    if (this.level == 0) {
      for (var j = 0; j < this.pane._tables.length; j++)
      if (this.pane._tables[j].gutterTreeNode) {
        expanded = this.pane._tables[j].gutterTreeNode.attr("expanded");
        if (!expanded) break;
      };
    }
    else {
      var found = false;
      for (var j = 0; j < this.pane._tables.length; j++) {

        if (this.pane._tables[j].gutterTreeNode) {
          expanded = this.pane._tables[j].gutterTreeNode.attr("expanded");
          if (!expanded) {
            found = true;
            break;
          }
        };

        for (var k = 0; k < this.pane._tables[j].totals.length; k++) {
          if (this.pane._tables[j].totals[k].level <= this.level) {
            for (var l = 0; l < this.pane._tables[j].totals[k].clones.length; l++)
            if (this.pane._tables[j].totals[k].clones[l].gutterTreeNode) {
              expanded = this.pane._tables[j].totals[k].clones[l].gutterTreeNode.attr("expanded");
              if (!expanded) {
                found = true;
                break;
              }
            }
          };
          if (found) break;
        };
        if (found) break;
      };
    }


    if (expanded) {
      this._collapse();
    }
    else {
      for (var i = 0; i <= this.level; i++) {
        this.pane._gutterLevels[i]._expand();
      }
    }

    if (topNode) setTimeout(function() {
      dojo.window.scrollIntoView(topNode);
    }, 20);
  }


});