<?xml version="1.0" encoding="UTF-8"?>
<rmml>
<!--
$RCSfile: rnmc_utils.xml,v $
$Revision: 1002 $

last change: $Date: 2009-03-12 11:25:08 +0300 (Чт, 12 мар 2009) $
             $Author: antonio $

  Lacerta Project
  version 1.0.0.1
  Copyright (C) 2007-2009 RNMC
-->

<composition name="rnmc_Utils">
<script src="CountResultAlgorithms.mjs"/>
<script><![CDATA[
  // sprintf fo Java Script ================================================
  // Copyright (c) 2007 Alexandru Marasteanu <http://alexei.417.ro/>
  // Thanks to David Baird (unit test and patch).

  function str_repeat(i, m) { for (var o = []; m > 0; o[--m] = i); return(o.join('')); }

  function sprintf () {
    var i = 0, a, f = arguments[i++], o = [], m, p, c, x;
    while (f) {
      if (m = /^[^\x25]+/.exec(f)) o.push(m[0]);
      else if (m = /^\x25{2}/.exec(f)) o.push('%');
      else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) {
        if (((a = arguments[m[1] || i++]) == null)
          || (a == undefined))
          throw("Too few arguments.");

        if (/[^s]/.test(m[7]) && (typeof(a) != 'number'))
          throw("Expecting number but found " + typeof(a));

        switch (m[7]) {
          case 'b': a = a.toString(2); break;
          case 'c': a = String.fromCharCode(a); break;
          case 'd': a = parseInt(a); break;
          case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break;
          case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break;
          case 'o': a = a.toString(8); break;
          case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break;
          case 'u': a = Math.abs(a); break;
          case 'x': a = a.toString(16); break;
          case 'X': a = a.toString(16).toUpperCase(); break;
        }
        a = (/[def]/.test(m[7]) && m[2] && a > 0 ? '+' + a : a);
        c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' ';
        x = m[5] - String(a).length;
        p = m[5] ? str_repeat(c, x) : '';
        o.push(m[4] ? a + p : p + a);
      }
      else
        throw ("Huh ?!");

      f = f.substring(m[0].length);
    }
    return o.join('');
  }

// ==================================================================
// Функция убирает пробельные литеры начале
  function ltrim(str){
    return str.replace(/^\s+/, '');
  }

// ==================================================================
// Функция убирает пробельные в конце
  function rtrim(str){
    return str.replace(/\s+$/, '');
  }  

// ==================================================================
// Функция убирает пробельные литеры в начале и конце строки
  function trim(str){
    return str.replace(/(^\s+)|(\s+$)/g, '');
  }

// ==================================================================
// Функция собирает путь из двух частей
  function makePathSrc(base, relative){
    if (relative.length > 0 && relative[0] != '/'
    && relative[0] != '\\')
    // Если относительный путь начинается с символов символов '/', '\',
    // то считаем что он абсолютный
      return makePath(base, relative);
    else
      return relative;
  }
  function makePath(base, relative){
    if (!base)
      return relative;

  // Если относительный путь начинается с указания протокола ('http://' и т. д.),
  // считаем что он абсолютный
    if (/(\S+)(?=:\/{0,2})/i.exec(relative))
      return relative;

    var re = new RegExp("/", "g");

    var splitBase     = new String(base).replace(re, "\\").split("\\");
    var splitRelative = new String(relative).replace(re, "\\").split("\\");

  // удаляем если в конце стояли \ или /
    if (splitBase[splitBase.length-1] == "")
      splitBase.pop();

    while ( true){
      if (splitRelative[0] == ".")
        splitRelative.shift();
      else if (splitRelative[0] == ".."){
        splitRelative.shift();
        splitBase.pop();
      }
      else
        break;
    }

    var strResult = splitBase.join("\\");
    strResult += "\\";
    strResult += splitRelative.join("\\");

    return strResult;
  }
  
// == Функция открытия XML-файла ===
  function openXML(path){
    if(!resourceExists(path)){
      trace("ОШИБКА: XML-файл " + path + " не найден.");
      return null;
    }

    var XMLfile = new XML();
    XMLfile.src = path;
    if (!XMLfile.XMLDocument){
      trace("XML-файл " + path + " не является правильным XML файлом.");
      return null;
    }

    XMLfile.XMLDocument.source = path;
    return XMLfile;
  }

// =======================================================================================
// функция осуществляет разбор ссылок и производит действия:

// Специально для некоторых модулей 
  function findObjectEverywhereByName(objName, objlist)
  {
    var res = null;
    if (objlist != null && objName != null) {
      for(var i = 0; i < objlist.length && res == null; ++i){
        if (objlist[i].id==objName) 
          res=objlist[i];
        else {
          if (objlist[i].childObjects!=null)
            res = findObjectEverywhereByName(objName, objlist[i].childObjects);
        }
      }
    }

    return(res);
  }

  function fireLink(hRef, ownerObject){
    var href = unescape(hRef);

  // Специально для некоторых модулей 
    var thePos = href.indexOf(":");
        var theType =  href.slice(0, thePos);
        var theSrc = href.slice(thePos + 1);

        if (theType == "step"){
      scene.Labwork.currentStep.dispatchAction(new Array("goToStep",theSrc));
      return;
    }

    if (theType == "mmdata"){
      curInfo = findObjectEverywhereByName("info",scene.Labwork.currentStep.childObjects);
      curFirstImg = findObjectEverywhereByName("firstimg",
        scene.Labwork.currentStep.childObjects);

      if (curInfo != null){
        curInfo.doAction(new Array("hideAllObjects",""));
        curInfo.showObject();
        for(var i = 0; i < curInfo.childObjects.length; ++i){
          if(curInfo.childObjects[i].id == theSrc)
            curInfo.childObjects[i].showObject();
          else
            curInfo.childObjects[i].hideObject();  
        }
      }

      if (curFirstImg != null)
        curFirstImg.hideObject();
    }

    var result = /(\S+)(?=:\/{0,2})/i.exec(href);
    if (result != null){
    // ссылки вида http: https: ftp: mailto: oms-module: - будут обработаны автоматически
      if (/http|https|ftp|mailto|oms-module/i.test(result[1])){
        Player.module.gotoLink(href);
      } else if (/eHint/i.test(result[1])){

        if (!scene.Hint)
          return;

        result = /type(?=\s*=\s*(\S+?)(?=[\s*&$]))/i.exec(href);
        if (result != null)
        {
          var position = this.globalToLocal(Mouse.x, Mouse.y+20);
          if (result[1].toLowerCase() == "text")
          {
            result = /src(?=\s*=\s*(\S+?)(?=&|$))/i.exec(href);
            if (result != null) {
              if (ownerObject != undefined && "src" in ownerObject){
                var tmp = new String(ownerObject.src).replace("/\/.g", "\\").split("\\")
                tmp.pop();
                scene.Hint.showExternalTextHint(
                  scene.Utils.makePathSrc(tmp.join("\\"), result[1]),
                  position.x, position.y);
              }
              else
                scene.Hint.showExternalTextHint(result[1], position.x, position.y)
            }
            else
            {
              result = /value(?=\s*=(.*?)(?=&|$))/i.exec(href);
              if (result != null)
                scene.Hint.showTextHint(result[1], position.x, position.y);
            }
          }
          else if (result[1].toLowerCase() == "image")
          {
            result = /src(?=\s*=\s*(\S+?)(?=&|$))/i.exec(href);
            if (result != null)
            {
              var src = result[1];
              if (ownerObject != undefined && "src" in ownerObject){
                var tmp = new String(ownerObject.src).replace("/\/.g", "\\").split("\\")
                tmp.pop();
                src = scene.Utils.makePathSrc(tmp.join("\\"), result[1]);
              }

              result = /scale(?=\s*=\s*(\S+)(?=&|$))/i.exec(href);
              if (result != null)
                scene.Hint.showImageHint(src,
                  position.x, position.y, parseFloat(result[1]));
              else
                scene.Hint.showImageHint(src, position.x, position.y);
            }
          }
          else if (result[1].toLowerCase() == "video")
          {
            result = /src(?=\s*=\s*(\S+?)(?=&|$))/i.exec(href);
            if (result != null)
            {
              var src = result[1];
              if (ownerObject != undefined && "src" in ownerObject){
                var tmp = new String(ownerObject.src).replace("/\/.g", "\\").split("\\")
                tmp.pop();
                src = scene.Utils.makePathSrc(tmp.join("\\"), result[1]);
              }

              result = /scale(?=\s*=\s*(\S+)(?=&|$))/i.exec(href);
              if (result != null)
                scene.Hint.showVideoHint(src,
                  position.x, position.y, parseFloat(result[1]));
              else
                scene.Hint.showVideoHint(src, position.x, position.y);
            }
          }
          else if (result[1].toLowerCase() == "audio")
          {
            result = /src(?=\s*=\s*(\S+?)(?=&|$))/i.exec(href);
            if (result != null)
            {
              var src = result[1];
              if (ownerObject != undefined && "src" in ownerObject){
                var tmp = new String(ownerObject.src).replace("/\/.g", "\\").split("\\")
                tmp.pop();
                src = scene.Utils.makePathSrc(tmp.join("\\"), result[1]);
              }
              scene.Hint.showVideoHint(src, position.x, position.y);
            }
          } else {
            switch (result[1].toLowerCase()){
              case "text":
              case "image":
              case "video":
              case "audio":

              case "quicktime":
              case "qtemul":
              case "flash":
              case "slideshow":
              case "animation":
              case "shape":
              case "object3D": {
                var objName = result[1].toLowerCase();
                result = /src(?=\s*=\s*(\S+?)(?=&|$))/i.exec(href);
                if (result != null){
                  var src = result[1];
                  if (ownerObject != undefined && "src" in ownerObject){
                    var tmp = new String(ownerObject.src).replace(
                      "/\/.g", "\\").split("\\")
                    tmp.pop();
                    src = scene.Utils.makePathSrc(tmp.join("\\"), result[1]);
                  }
              
                  result = /scale(?=\s*=\s*(\S+)(?=&|$))/i.exec(href);
                  if (result != null)
                    scene.Hint.showObjectHint(objName,
                      src, position.x, position.y, parseFloat(result[1]));
                  else
                    scene.Hint.showObjectHint(objName,
                      src, position.x, position.y);
                }
              } break;
            }
          }
        }
      } else if (/Event/i.test(result[1])){
      //    вызов диспетчера
        if (ownerObject != 'undefined' && ownerObject != null){
          while (ownerObject){
            if ("dispatchAction" in ownerObject)
              break;
            ownerObject = ownerObject.parent;
          }

          if (!ownerObject)
            return;

          var actions_string = href.slice(8);
          var theActions = new Array();

          var actions = (actions_string).split(";");
          for(var i = 0; i < actions.length; i++){
            var parsedCommand = actions[i].split(":");
            ownerObject.dispatchAction(parsedCommand);
          }
        }
      }
    }
  }

//======================================================================================
// функция осуществляет случайную подстановку на массиве
// если указан itemsTotal, то в результирующем массиве
// возвращаются только itemsTotal случайных элементов из originalArray
  function permutateArray(originalArray, itemsTotal){
    var numberArray = new Array();
    var newArray = new Array();

    if(originalArray instanceof Array){
      var itemFound = false;
      var itemIndex = 0;
      if(!itemsTotal || itemsTotal == undefined || itemsTotal > originalArray.length)
        itemsTotal = originalArray.length;
      for(var i = 0; i < itemsTotal; i++){
        itemFound = false;
        while(!itemFound){
          itemIndex = Math.round(Math.random()*itemsTotal);
          if(itemIndex != undefined && itemIndex < itemsTotal){
            if(getOne(itemIndex, numberArray) == -1){
              itemFound = true;
              numberArray.push(itemIndex);
            }
          }
        }
      }
      for(var i = 0; i < numberArray.length; i++){
        newArray.push(originalArray[numberArray[i]]);
      }
      numberArray = null;
      return newArray;
    } else {
trace("ERROR: permutateArray: originalArray is not an instanceof Array.");
    }
  }

// ==================================================================
// функция ищет положение заданного элемента в массиве
// если элемент не найден, возвращается -1
  function getOne(nItem, searchInArray){
    var nFound = -1;
    for(var i = 0; i < searchInArray.length; i++){
      if(searchInArray[i] == nItem){
        nFound = i;
        break;
      };
    };
    return nFound;
  };

// ==================================================================
//  функция замены подстроки в исходной строке
//  возвращает результирующую строку
  function replaceString(strSource, strFind, strReplace, intCount){
/*
    re = new RegExp(""+strFind, "g");
    var strProcessed = strSource.replace(re, strReplace);
    return strProcessed;
*/


    var strProcessed = "";
    while (true) {
      var i = strSource.indexOf(strFind);
      if (i >= 0) {
        strProcessed = strProcessed + strSource.substr(0, i) + strReplace;
        strSource = strSource.substr(i + strFind.length);
      }else break;
    }

    return strProcessed + strSource;
  };
  
// ==================================================================
//  функция замены подстроки в исходной строке
//  возвращает результирующую строку,
//  в отличии от предыдущей версии строчка должна заканчиваться
//  специальным символом ('конец строки', ';' )
  function replaceString2(strSource, strFind, strReplace, intCount){
    result = new String(strSource);
    result = result.replace(strFind, strReplace);
    return result;
  }

// ==================================================================
// функция переводит число секунд в формат минуты:секунды
// если displayHours == true то в формате  часы:минуты:секунды
  function translateSecondsToString(secondsValue, displayHours){
    if(secondsValue < 0)
      return "-";
    var seconds = secondsValue % 60;
    var minutes = parseInt(((secondsValue - seconds)/60) % 60);
    var hours = parseInt(((secondsValue - minutes*60) - seconds)/3600);
    var resultStr = "";
    if(displayHours == true){
      if(hours < 10)
        resultStr = resultStr + "0";
      resultStr = resultStr + hours + ":";
    }
    if(minutes < 10)
      resultStr = resultStr + "0";
    resultStr = resultStr + minutes + ":";
    if(seconds < 10)
      resultStr = resultStr + "0";
    resultStr = resultStr + seconds;
    return resultStr;
  }

//  переводит секунды в строку с заданным форматом
  function translateSecondsToTimeFormat(secondsValue, timeFormat){
    var seconds = secondsValue % 60;
    var minutes = parseInt(((secondsValue - seconds)/60) % 60);
    var hours = parseInt(((secondsValue - minutes*60) - seconds)/3600);
    var secondsStr = "";
    var minutesStr = "";
    var hoursStr = "";
    if(seconds < 10)
      secondsStr = secondsStr + "0";
    secondsStr = secondsStr + seconds;
    if(minutes < 10)
      minutesStr = minutesStr + "0";
    minutesStr = minutesStr + minutes;
    if(hours < 10)
      hoursStr = hoursStr + "0";
    hoursStr = hoursStr + hours;
    var formatString = timeFormat;
    var re = new RegExp("(SS)", "g");
    formatString = formatString.replace(re, secondsStr);
    re = new RegExp("(MM)", "g");
    formatString = formatString.replace(re, minutesStr);
    re = new RegExp("(HH)", "g");
    formatString = formatString.replace(re, hoursStr);
    return formatString;
  }

  function getSeconds(secondsValue, doubleDigit){
    var resultStr = "";
    var seconds = secondsValue % 60;
    if(doubleDigit == true && seconds < 10){
      resultStr = resultStr + "0";
    }
    resultStr = resultStr + seconds;
    return resultStr;
  }

//  
  function getMinutes(secondsValue, doubleDigit){
    var resultStr = "";
    var seconds = secondsValue % 60;
    var minutes = parseInt(((secondsValue - seconds)/60) % 60);
    if(doubleDigit == true && minutes < 10){
      resultStr = resultStr + "0";
    }
    resultStr = resultStr + minutes;
    return resultStr;
  }

//  возвращает строчку
  function getHours(secondsValue, doubleDigit){
    var resultStr = "";
    var seconds = secondsValue % 60;
    var minutes = parseInt(((secondsValue - seconds)/60) % 60);
    var hours = parseInt(((secondsValue - minutes*60) - seconds)/3600);
    if(doubleDigit == true && hours < 10){
      resultStr = resultStr + "0";
    }
    resultStr = resultStr + hours;
    return resultStr;
  }

// ==================================================================
// функция переводит Date в строку часы:минуты:секунды
  function translateDateToString(dateValue){
    if(dateValue instanceof Date){
      var hours = dateValue.getHours();
      var minutes = dateValue.getMinutes();
      var seconds = dateValue.getSeconds();
      var resultStr = "";
      if(hours < 10)
        resultStr = resultStr + "0";
      resultStr = resultStr + hours + ":";
      if(minutes < 10)
        resultStr = resultStr + "0";
      resultStr = resultStr + minutes + ":";
      if(seconds < 10)
        resultStr = resultStr + "0";
      resultStr = resultStr + seconds;
      return resultStr;
    }
  }

// ==================================================================
//   функция переводит строку '[x,y,width,height]'
//     в массив Array[x,y,width,height]
  function parseRectToArray(rectValue){
    var rectString = rectValue.slice(1, (rectValue.length - 1));
    var rectParams = rectString.split(",");
    var resultArray = new Array();
    if(rectParams.length == 4){
      for(var i = 0; i < rectParams.length; i++)
        resultArray.push(parseInt(rectParams[i]));
      return resultArray;
    } else {
      return null;
    }
  }

  function parsePolygonToArray(polygonString){
    var resultArray = new Array();
    var tempString = polygonString.slice(2, (polygonString.length - 2));
    tempString = scene.Utils.replaceString(tempString, "),(", ";");
    var polygonPoints = tempString.split(";");
    if(polygonPoints && polygonPoints.length > 0){
      for(var i = 0; i < polygonPoints.length; i++){
        if(polygonPoints[i] != ""){
          var pointParams = polygonPoints[i].split(",");
          var newPoint = new Object();
          newPoint.x = parseInt(pointParams[0]);
          newPoint.y = parseInt(pointParams[1]);
          resultArray.push(newPoint);
        }
      }
    }
    if(resultArray.length > 0){
      return   resultArray;
    } else {
      resultArray = null;
      return null;
    }
  }

//  разбирает узел action и возвращает массив
  function parseActionFromNode(actionNode){
    var newActions = new Array();
    var parsedCommand = null;
    var xmlAttributeMap = null;
    var xmlAttribute = null;

    if(actionNode.nodeName == "action"){
      if(actionNode.textContent != null){
        var actionId = null;
        var actionEvent = null;
        var eventParam = null;
        xmlAttributeMap = actionNode.attributes;
        if (xmlAttributeMap){
          xmlAttribute =  xmlAttributeMap.getNamedItem("id");
          if (xmlAttribute != null && xmlAttribute.specified){
            actionId = xmlAttribute.value;
          }
          xmlAttribute =  xmlAttributeMap.getNamedItem("event");
          if (xmlAttribute != null && xmlAttribute.specified){
            actionEvent = xmlAttribute.value;
          }
          xmlAttribute =  xmlAttributeMap.getNamedItem("eventParam");
          if (xmlAttribute != null && xmlAttribute.specified){
            eventParam = xmlAttribute.value;
          }
        }  
        if(actionNode.textContent){
//trace("actionNode.textContent == "+actionNode.textContent);
        //  trim whitespace
          var content = actionNode.textContent;
				// Данная конструкция удаляла пробелы
        // внутри текстовых хинтов вставленых непосредственно в файл описания сцены,
        // поэтому и был закоментировал
//          content = scene.Utils.replaceString(content, " ", "");
          content = scene.Utils.replaceString(content, "\r", "");
          content = scene.Utils.replaceString(content, "\t", "");
          content = scene.Utils.replaceString(content, "\n", "");
        // Сначало выдели специальные команды - asyncAction:{<список команд>};
          var result = /asyncAction:{(.*)}/g.exec(content);
          if (result)
          {
            content = content.replace(/asyncAction:{(.*)}/g, "");
            for(var k = 1; k < result.length; ++k){
              var actions = (result[k]).split(";");
              for(var i = 0; i < actions.length; i++){
                var parsedCommand = null;
                var newCommand = actions[i].split(":");
                if(newCommand.length > 2){
                  for (var j = 2; j < newCommand.length; ++j){
                    newCommand[1] += ":" + newCommand[j]
                  }
                  parsedCommand = new Array(newCommand[0], newCommand[1]);
                }
                else
                  parsedCommand = newCommand;

                if (parsedCommand != null){
                  if(actionId)
                    parsedCommand.id = actionId;
                  if(actionEvent)
                    parsedCommand.event = actionEvent;
                  if(eventParam)
                    parsedCommand.eventParam = eventParam;
                  newActions.push(new Array("asyncAction", parsedCommand));
                }
              }
            }
          }

          var actions = (content).split(";");
          for(var i = 0; i < actions.length; i++){
            var parsedCommand = null;
            var newCommand = actions[i].split(":");

          // Убрать пробелы в начале и в конце строк 
            for (var j = 0; j < newCommand.length; ++j)
              scene.Utils.trim(newCommand[j]);

            if(newCommand.length > 2){
              for (var j = 2; j < newCommand.length; ++j){
                newCommand[1] += ":" + newCommand[j]
              }
              parsedCommand = new Array(newCommand[0], newCommand[1]);
            }
            else
              parsedCommand = newCommand;

            if (parsedCommand != null){
              if(actionId)
                parsedCommand.id = actionId;
              if(actionEvent)
                parsedCommand.event = actionEvent;
              if(eventParam)
                parsedCommand.eventParam = eventParam;
              newActions.push(parsedCommand);
            }
          };
        } else {
          return;
        }
      } else {
      // если нет текста внутри тега
        return;
      }
    }
    return newActions;
  }

// 
  function parseActionsNode(actionsNode, onlyForEvent){
    var actions = new Array();
    var xmlNode = null;
    var xmlAttributeMap = null;
    var xmlAttribute = null;

    xmlNode = actionsNode.firstChild;
    while(xmlNode){
      if(xmlNode.nodeName == "action"){
        if(onlyForEvent == undefined){
          var subActions = this.parseActionFromNode(xmlNode);
          if(subActions){
            for(var i = 0; i < subActions.length; i++){  
              actions.push(subActions[i]);
            }
          }
        } else {
          xmlAttributeMap = xmlNode.attributes;
          if (xmlAttributeMap){
            xmlAttribute =  xmlAttributeMap.getNamedItem("event");
            if (xmlAttribute != null
            && xmlAttribute.specified
            && xmlAttribute.value == onlyForEvent){
              var subActions = this.parseActionFromNode(xmlNode);
              if(subActions){
                for(var i = 0; i < subActions.length; i++){  
                  actions.push(subActions[i]);
                }
              }
            }
          }
        }
      }
      xmlNode = xmlNode.nextSibling;
    }
    return actions.length == 0 ? null : actions;
  }

//  =================================================================
//  валидатор последовательности скобок
  function validateConditionFormat(conditionString){
    //  стек для типов скобок
    var parenthesesStack = new Array();
    //  0 == {
    //  1 == (
    //  2 == [
    for(var i = 0; i < conditionString.length; i++){
      switch(conditionString[i]){
      case "{":
        parenthesesStack.push(0);
        break;
      case "}":
        var lastParenthese = parenthesesStack.pop();
        if(lastParenthese != 0)
          return false;
        break;
      case "(":
        parenthesesStack.push(1);
        break;
      case ")":
        var lastParenthese = parenthesesStack.pop();
        if(lastParenthese != 1)
          return false;
        break;
      case "[":
        parenthesesStack.push(2);
        break;
      case "]":
        var lastParenthese = parenthesesStack.pop();
        if(lastParenthese != 2)
          return false;
        break;
      }
    }
    return true;
  }

//  =================================================================
// функция вычисляет координаты объекты вписывамого в некоторый прямоугольник
  function calculateCoords(destinationRectX, destinationRectY,
              destinationRectWidth, destinationRectHeight,
              objectWidth, objectHeight, methodId){
    var newDimensions = new Array();
    var newX = 0;
    var newY = 0
    var newWidth = 0;
    var newHeight = 0;
    var originalProp = objectWidth/objectHeight;
    var destProp = destinationRectWidth/destinationRectHeight;

    if(originalProp >= 1){  // horizontal or square
      if(originalProp < destProp){
        newHeight = destinationRectHeight;
        newWidth = (objectWidth/objectHeight) * destinationRectHeight;
      } else if(originalProp > destProp){
        newWidth = destinationRectWidth;
        newHeight = (objectHeight/objectWidth) * destinationRectWidth;
      } else{
        newWidth = objectWidth;
        newHeight = objectHeight;
      }
    } else {        // vertical
      if(originalProp < destProp){
        newHeight = destinationRectHeight;
        newWidth = (objectWidth/objectHeight) * destinationRectHeight;
      } else if(originalProp > destProp){
        newWidth = destinationRectWidth;
        newHeight = (objectHeight/objectWidth) * destinationRectWidth;
      } else{
        newWidth = objectWidth;
        newHeight = objectHeight;
      }
    }

    newX = destinationRectX + (destinationRectWidth - newWidth)/2;
    newY = destinationRectY + (destinationRectHeight - newHeight)/2;

    newDimensions.push(newX);
    newDimensions.push(newY);
    newDimensions.push(newWidth);
    newDimensions.push(newHeight);
    return newDimensions;
  }

// ==============================================================
//  функции инициализации стандартных элементов
// ==============================================================
//  векторный примитив
  function initStdShapeFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "shape"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdShape";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

//  текст
  function initStdTextFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "text"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdText";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

//  поле ввода текста
  function initStdInputFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "input"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdInput";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

//  поле ввода текста
// основанное на Text()
  function initStdInputExFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "input_ex"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdInputEx";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }
  
//  изображение
  function initStdImageFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "image"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdImage";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

  function initStdAudioFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "audio"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdAudio";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

  function initStdVideoFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "video"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdVideo";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

// Анимация  
  function initStdFlashFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "flash"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdFlash";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

  function initStdQTFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "quicktime"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdQuickTime";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

  function initStdAnimationFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "animation"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdAnimation";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

  function initStdQTEmulFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "qtemul"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdQTEmulation";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

  function initStdTimerFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "timer"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdTimer";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

  function initStd3DObjectFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "object3D"){
      var newObject = new Composition();
      newObject._class = "rnmc_std3DObject";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

  function initStdCollectionFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "collection"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdCollection";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

  function initStdSlideshowFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "slideshow"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdSlideshow";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

  function initStdMediaGroupFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "group"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdMediaGroup";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

  function initStdZoneFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "zone"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdZone";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

// ========================================================
// controls
  function initStdButtonFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "button"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdButton";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    };
  }

  function initStdPlaycontrolFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "playcontrol"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdPlayControl";
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    };
  }

  function initStdGroupFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "group"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdControlGroup";
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    };
  }

  function initEffectFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "effect"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdEffect";
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    };
  }

//  =====================================
  function initCrosswordFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "crossword"){
      var newObject = new Composition();
      newObject._class = "rnmc_Crossword";
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

  function initStdSliderFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "slider"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdSlider";
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    };
  }
//  =====================================
  function initRectangleFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "rectangle"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdRectangle";
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    };
  }

//  =====================================
  function initDraggingFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "dragging"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdDragging";
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    };  
  }

//  =====================================
  function initQuestionFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "question"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdQuestion";
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }
//  =====================================
  function initUnionFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "union"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdUnion";
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }

//	=====================================
	function initStdIntegrationFromNode(srcNode, parentObject){
		if(srcNode.nodeName == "integration"){
			var newObject = new Composition();
			newObject._class = "rnmc_stdIntegration";
			newObject.parent = parentObject;
			newObject.integrationInit = true;
			if(newObject.initFromNode(srcNode)){
				return this.postInitObjectFromNode(srcNode, newObject);
			} else {
				newObject.parent = null;
				newObject = null;
				return null;
			}
		}
	}  

//	=====================================
	function initStdDraglistFromNode(srcNode, parentObject){
		if(srcNode.nodeName == "draglist"){
			var newObject = new Composition();
			newObject._class = "rnmc_stdDraglist";
			newObject.parent = parentObject;
			newObject.draglistInit = true;
			if(newObject.initFromNode(srcNode)){
				return this.postInitObjectFromNode(srcNode, newObject);
			} else {
				newObject.parent = null;
				newObject = null;
				return null;
			}
		}
	}
	
//	=====================================
	function initStdCalculatorFromNode(srcNode, parentObject){		
		if(srcNode.nodeName == "calculator"){
			var newObject = new Composition();
			newObject._class = "rnmc_stdCalculator";
			newObject.parent = parentObject;
			newObject.calculatorInit = true;
			if(newObject.initFromNode(srcNode)){
				return this.postInitObjectFromNode(srcNode, newObject);
			} else {
				newObject.parent = null;
				newObject = null;
				return null;
			}
		}
	}  

  function initStdElementFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "element"){
      xmlAttributeMap = srcNode.attributes;
      xmlAttribute =  xmlAttributeMap.getNamedItem("style");
      if (xmlAttribute != null && xmlAttribute.specified){
        var newObject = scene.ControlManager.getControl(xmlAttribute.value, parentObject);
        if (newObject){
          if (newObject.initFromNode(srcNode))
            return this.postInitObjectFromNode(srcNode, newObject);
          else
            newObject.parent = null;
        }
      }
    }

    return null;
  }

//  установить соответствие
  function initStdLineFromNode(srcNode, parentObject){
    if(srcNode.nodeName == "line"){
      var newObject = new Composition();
      newObject._class = "rnmc_stdLine";
      newObject.visible = false;
      newObject.parent = parentObject;
      if(newObject.initFromNode(srcNode)){
        return this.postInitObjectFromNode(srcNode, newObject);
      } else {
        newObject.parent = null;
        newObject = null;
        return null;
      }
    }
  }
  
  function postInitObjectFromNode(srcNode, Object){
    return Object;
  }

  function initStdObjectFromNode(xmlNode, parentObject){
    var newObject = null;
    switch (xmlNode.nodeName)
    {
      case "element":
        newObject = scene.Utils.initStdElementFromNode(xmlNode, parentObject);
        break;
      case "image":
        newObject = scene.Utils.initStdImageFromNode(xmlNode, parentObject);
        break;
      case "text":
        newObject = scene.Utils.initStdTextFromNode(xmlNode, parentObject);
        break;
      case "shape":
        newObject = scene.Utils.initStdShapeFromNode(xmlNode, parentObject);
        break;
      case "video":
        newObject = scene.Utils.initStdVideoFromNode(xmlNode, parentObject);
        break;
      case "audio":
        newObject = scene.Utils.initStdAudioFromNode(xmlNode, parentObject);
        break;
      case "flash":
        newObject = scene.Utils.initStdFlashFromNode(xmlNode, parentObject);
        break;
      case "quicktime":
        newObject = scene.Utils.initStdQTFromNode(xmlNode, parentObject);
        break;
      case "input":
        newObject = scene.Utils.initStdInputFromNode(xmlNode, parentObject);
        break;
      case "input_ex":
        newObject = scene.Utils.initStdInputExFromNode(xmlNode, parentObject);
        break;
      case "animation":
        newObject = scene.Utils.initStdAnimationFromNode(xmlNode, parentObject);
        break;
      case "qtemul":
        newObject = scene.Utils.initStdQTEmulFromNode(xmlNode, parentObject);
        break;
      case "object3D":
        newObject = scene.Utils.initStd3DObjectFromNode(xmlNode, parentObject);
        break;
      case "collection":
        newObject = scene.Utils.initStdCollectionFromNode(xmlNode, parentObject);
        break;
      case "slideshow":
        newObject = scene.Utils.initStdSlideshowFromNode(xmlNode, parentObject);
        break;
      case "button":
        newObject = scene.Utils.initStdButtonFromNode(xmlNode, parentObject);
        break;
      case "timer":
        newObject = scene.Utils.initStdTimerFromNode(xmlNode, parentObject);
        break;
      case "group":
        newObject = scene.Utils.initStdMediaGroupFromNode(xmlNode, parentObject);
        break;
      case "zone":
        newObject = scene.Utils.initStdZoneFromNode(xmlNode, parentObject);
        break;
      case "crossword":
        newObject = scene.Utils.initCrosswordFromNode(xmlNode, parentObject);
        break;
      case "rectangle":
        newObject = scene.Utils.initRectangleFromNode(xmlNode, parentObject);
        break;
      case "slider":
        newObject = scene.Utils.initStdSliderFromNode(xmlNode, parentObject);
        break;
      case "dragging":
        newObject = scene.Utils.initDraggingFromNode(xmlNode, parentObject);
        break;
      case "question":
        newObject = scene.Utils.initQuestionFromNode(xmlNode, parentObject);
        break;
      case "union":
        newObject = scene.Utils.initUnionFromNode(xmlNode, parentObject);
        break;
      case "integration":
        newObject = scene.Utils.initStdIntegrationFromNode(xmlNode, parentObject);
        break;
      case "line":
        newObject = scene.Utils.initStdLineFromNode(xmlNode, parentObject);
	  case "draglist":
		newObject = scene.Utils.initStdDraglistFromNode(xmlNode, parentObject);
        break;
	  case "calculator":
		newObject = scene.Utils.initStdCalculatorFromNode(xmlNode, parentObject);
        break;
      default:
        if (scene.CustomUtils.initStdObjectFromNodeCustom)
          newObject = scene.CustomUtils.initStdObjectFromNodeCustom(xmlNode, parentObject);
        break;
    }

    return newObject;
  }
  
// функция возвращает стиль 
  function getAutoAttachStyle(theStyleStr){
    theAutoAttachStyle = null;
    switch(theStyleStr){
      case "LEFT_ABOVE":
        theAutoAttachStyle = AUTOATTACH_LEFT_ABOVE;
        break;
      case "LEFT_TOP":
        theAutoAttachStyle = AUTOATTACH_LEFT_TOP;
        break;
      case "LEFT_CENTER":
        theAutoAttachStyle = AUTOATTACH_LEFT_CENTER;
        break;
      case "LEFT_BOTTOM":
        theAutoAttachStyle = AUTOATTACH_LEFT_BOTTOM;
        break;
      case "LEFT_BELOW":
        theAutoAttachStyle = AUTOATTACH_LEFT_BELOW;
        break;
      case "TOP_LEFT":
        theAutoAttachStyle = AUTOATTACH_TOP_LEFT;
        break;
      case "TOP_CENTER":
        theAutoAttachStyle = AUTOATTACH_TOP_CENTER;
        break;
      case "TOP_RIGHT":
        theAutoAttachStyle = AUTOATTACH_TOP_RIGHT;
        break;
      case "RIGHT_ABOVE":
        theAutoAttachStyle = AUTOATTACH_RIGHT_ABOVE;
        break;
      case "RIGHT_TOP":
        theAutoAttachStyle = AUTOATTACH_RIGHT_TOP;
        break;
      case "RIGHT_CENTER":
        theAutoAttachStyle = AUTOATTACH_RIGHT_CENTER;
        break;
      case "RIGHT_BOTTOM":
        theAutoAttachStyle = AUTOATTACH_RIGHT_BOTTOM;
        break;
      case "RIGHT_BELOW":
        theAutoAttachStyle = AUTOATTACH_RIGHT_BELOW;
        break;
      case "BOTTOM_LEFT":
        theAutoAttachStyle = AUTOATTACH_BOTTOM_LEFT;
        break;
      case "BOTTOM_CENTER":
        theAutoAttachStyle = AUTOATTACH_BOTTOM_CENTER;
        break;
      case "BOTTOM_RIGHT":
        theAutoAttachStyle = AUTOATTACH_BOTTOM_RIGHT;
        break;    
    }
    return theAutoAttachStyle;
  }
]]></script>
</composition>
</rmml>
