Resizer multi-prims

All description in first comments of the script.
Maybe my English is not so good (I'm French). Hope anyone will understand.
Update on october 11th, 2010
Autodetect official LL grids or opensim
Resizer
/* =================================================================================== */
/* */
/* Resizer v1.5 */
/* */
/* License : */
/* Français */
/* OpenSource. Licence GPL 2 et plus. */
/* Modification, Copie et Transfert autorisés */
/* Sous condition de laisser le script en full perm (Modify / Copy / Transfer) */
/* */
/* English */
/* OpenSource. License GPL 2 and later. */
/* Modify, Copy and Transfer allowed if this script stay full perm */
/* */
/* Auteurs : Christy Mansbridge / Mingyar Ishtari, le 02 octobre 2010 */
/* */
/* Modifications / Updates : */
/* Author : Christy Mansbridge */
/* Date : 11 octobre 2010 */
/* Detail : Auto detection opensim/LL grids (version 1.4) */
/* */
/* Modifications / Updates : */
/* Author : Christy Mansbridge */
/* Date : 30 octobre 2010 */
/* Detail : Limitation déplacement limité à 10m sur opensim (version 1.5) */
/* */
/* Author : */
/* Date : */
/* Detail : */
/* */
/* Usage : */
/* Français */
/* À placer dans le prim root (prim coutouré en jaune à l'édition) */
/* Cliquer l'objet pour obtention du menu bleu. */
/* Usage restreint au seul propriétaire. */
/* */
/* English */
/* Place the script in the root prim of the build. */
/* Click the object to get the blue menu. */
/* Usage restricted to the owner. */
/* */
/* Fonctions : */
/* Français */
/* 1) Script de redimensionnement d'un objet multi-prims respectant les */
/* proportions, en taille et en position, de chaque prim. */
/* */
/* 2) Lag minimal puisqu'un seul script par objet (1 à 256 prims) */
/* Possibilité offerte de supprimer le script. */
/* */
/* 3) Communication avec d'autres objets pour synchroniser le redimensionnement */
/* Pour permettre cette communication, plusieurs critères douvent être remplis*/
/* a) L'objet doit être porté ainsi que celui/ceux à synchroniser */
/* b) Les objets doivent porter le même nom, à l'exception de la partie */
/* finale séparée du reste par un espace. */
/* Exemple : Chaussure rouge gauche et Chaussure rouge droite */
/* */
/* 4) Garantie de la conservation de l'intégrité de l'objet. */
/* a) Si un agrandissement entraine une destruction du build, */
/* Retour automatique à la taille avant agrandissement. */
/* */
/* b) Si l'objet contient au moins un huge prim le script reste inactif. */
/* Cette sécurité résevée à la grille officielle SecondLife peut être */
/* désactivée pour opensim en passant à TRUE l'affectation de la variable */
/* globale iAllowResizeHugePrims. */
/* */
/* 5) Prise en compte automatique des changements de liens (ajout/suppresion de */
/* prims ou redimensionnement manuel) */
/* */
/* 6) 18 choix de redimensionnement prédéfinis en pourcentages : */
/* -1, -2, -5, -10, -25, -50, -75, -85, -95. */
/* +1, +2, +5, +10, +25, +50, +75, +100, +200, */
/* */
/* 7) 3 choix extrèmes : Dimensionnement Minimal, Maximal et par Défaut. */
/* La dimension par défaut est celle à l'initialisation du script ou */
/* celle affectée par le menu [Set default]. */
/* */
/* 8) Détermination de la taille maximale avant déformation de la construction */
/* Pour trouver la taille maximale possible, procéder ainsi : */
/* Effectuer des agrandissements à +200% jusqu'à refus de dimensionnement */
/* Répéter l'opération avec les pourcentages inférieurs, +100% puis +75% */
/* puis 50% ... jusqu'à répétition de l'opétation à +1%. */
/* Après un refus de redimensionnement à +1% le script connait la vraie */
/* taille maximale. */
/* */
/* English */
/* 1) Script to resize a multi prims object with conservation of its integrity */
/* (size and relative position of each prim). */
/* */
/* 2) Less lag : only 1 script for an object (1 to 256 prims) */
/* Possibility to remove the script by the menu. */
/* */
/* 3) Communication with other objects to synchronize resize */
/* To allow communication, objects have to comply with few criteria : */
/* a) The object has to be worn, objects to synchronize too. */
/* b) Objects have to have same name except last part separated by space */
/* Example : Excelsior shoes Left and Excelsior shoes Right */
/* */
/* 4) Integrity waranty. */
/* a) If after increasing size the build is broken, automatic go back to */
/* previous good size. */
/* */
/* b) If, at least, one huge prim is in the build, the script is inactive. */
/* This security is only for official grid SecondLife and may be bypassed */
/* for opensim, affecting TRUE to the iAllowResizeHugePrims global variable*/
/* */
/* 5) Automatic detection of manual scale change and link changes */
/* */
/* 6) 18 predefined resize choice in percentage : */
/* -1, -2, -5, -10, -25, -50, -75, -85, -95. */
/* +1, +2, +5, +10, +25, +50, +75, +100, +200, */
/* */
/* 7) 3 other choices : Resize to Minimum, Maximum or Default size. */
/* The default size is the size at initialisation of the script or the size */
/* affected by the blue menu [Set default]. */
/* */
/* 8) How to find the real maximum size ? */
/* To find the real value : */
/* Make an increase size by +200% until the script says it fails. */
/* Then, repeat this method with +100%, then after with +75% ... */
/* After the last increase with +1% the real maximum size is found and */
/* stored by the script. */
/* */
/* =================================================================================== */
integer iAllowResizeHugePrims = -1; // You can force to FALSE on official SecondLife grids and TRUE on opensim
integer iNumberOfPrims;
integer iFirst;
integer iLast;
integer iBcl;
integer iIdx;
integer iDeb;
integer iFin;
integer iSens;
float fTmp;
vector vSize;
vector vPos;
float fMin;
float fMax;
float fFactor;
float fDefault;
integer iCanalComm = -8547548;
integer iCanalMenu;
integer iEcouteMenu;
integer iMenuOn;
integer iCurrentMenu;
string sPctM1 = "1";
string sPctM2 = "2";
string sPctM3 = "5";
string sPctP1 = "1";
string sPctP2 = "2";
string sPctP3 = "5";
string sPct;
integer iNbPasses;
integer iHugeUsed;
float fLimiteMax;
integer iNoMoreMax;
vector vPos1;
integer iError;
list lSortPrims;
list lSizes;
list lPos;
list lElem;
list lName;
// Hack to increase speed of the script (Mono)
Booster()
{
 for( iBcl = 0; iBcl < 5000; iBcl++ );
}
// Function to get size and/or relative position of the current prim
GetSizePos()
{
 vSize = llList2Vector( llGetLinkPrimitiveParams( iBcl, [ PRIM_SIZE ] ), 0 ) * fFactor;
 if( iBcl == iFirst )
 {
 if( llGetAttached() )
// Root prim and object attached to the avatar, position is local
 vPos = llGetLocalPos();
 else
// Root prim and object not attached, position is absolute position
 vPos = llGetRootPosition();
 }
 else
// Child prim, position is relative to the root prim
 vPos = ( ( llList2Vector( llGetLinkPrimitiveParams( iBcl, [ PRIM_POSITION ] ), 0 ) - llGetRootPosition() ) / llGetRootRotation() ) * fFactor;
}
// Function to control if current prim has expected size and relative position
ControlSizePos( vector vRefSize, vector vRefPos )
{
 if( llVecDist( llList2Vector( llGetLinkPrimitiveParams( iBcl, [ PRIM_SIZE ] ), 0 ), vRefSize ) > 0.001 )
 iError = TRUE;
 else if( iBcl != iFirst )
 {
 if( llVecDist( ( llList2Vector( llGetLinkPrimitiveParams( iBcl, [ PRIM_POSITION ] ), 0 ) - llGetRootPosition() ) / llGetRootRotation(),
 vRefPos ) > 0.001 )
 iError = TRUE;
 }
}
// Function to test resize validity of the current prim, if resize is over stored maximum size
integer TestError()
{
 if( fMax > fLimiteMax )
 ControlSizePos( vSize, vPos );
 return( iError );
}
// Function to control build integrity after resize
ControlBuild( integer iBoost )
{
 if( iBoost )
 Booster();
// No individual error found
// Control of all the build prim after prim
 for( iIdx = iDeb; iIdx != iFin; iIdx += iSens )
 {
 iBcl = llList2Integer( lSortPrims, iIdx );
 ControlSizePos( llList2Vector( lSizes, iIdx ) * fFactor, llList2Vector( lPos, iIdx ) * fFactor );
 if( iError )
 {
 if( iBoost )
 iIdx = iFin - iSens;
 return;
 }
 }
}
// Function to resize (only the size) each prim of the build
ChangeSize( integer iCorrect )
{
 Booster();
 for( iIdx = iDeb; iIdx != iFin; iIdx += iSens )
 {
 iBcl = llList2Integer( lSortPrims, iIdx );
 GetSizePos();
 if( iCorrect )
 vPos /= fFactor;
 llSetLinkPrimitiveParamsFast( iBcl, [ PRIM_SIZE, vSize ] );
 if( TestError() )
 return;
 }
}
// Function to adapt relative position of each prim of the build
ChangePos( integer iCorrect )
{
 Booster();
 for( iIdx = iDeb; iIdx != iFin; iIdx += iSens )
 if( ( iBcl = llList2Integer( lSortPrims, iIdx ) ) != iFirst )
 {
 GetSizePos();
 vPos1 = vPos / fFactor;
 if( iCorrect )
 vSize /= fFactor;
 llSetLinkPrimitiveParamsFast( iBcl, [ PRIM_POSITION, vPos ] );
 llSetLinkPrimitiveParamsFast( iBcl, [ PRIM_POSITION, vPos ] );
 llSetLinkPrimitiveParamsFast( iBcl, [ PRIM_POSITION, vPos ] );
 if( TestError() )
 return;
 }
}
// Function to resize and adapt relative position of each prim of the build
ChangeSizePos()
{
 Booster();
 for( iIdx = iDeb; iIdx != iFin; iIdx += iSens )
 {
 iBcl = llList2Integer( lSortPrims, iIdx );
 GetSizePos();
 llSetLinkPrimitiveParamsFast( iBcl, [ PRIM_SIZE, vSize, PRIM_POSITION, vPos ] );
 llSetLinkPrimitiveParamsFast( iBcl, [ PRIM_POSITION, vPos ] );
 llSetLinkPrimitiveParamsFast( iBcl, [ PRIM_POSITION, vPos ] );
 if( TestError() )
 return;
 }
}
// Function to resize and position each prim to the previous stored good sizes and relative positions after an error
GoBackToGoodSize()
{
 llOwnerSay( "Error, back to previous good size..." );
 sPct = "aborted";
 if( llRound( fFactor * 100.0 ) == 101 )
 iNoMoreMax = TRUE;
 fMin /= fFactor;
 fMax /= fFactor;
 iFin = iDeb - iSens;
 iDeb = iIdx;
 iSens *= -1;
 fFactor = 1.0;
 iNbPasses = 3;
 if( iNoMoreMax )
 fLimiteMax = fMax;
 do
 {
 Booster();
 iError = FALSE;
 for( iIdx = iDeb; iIdx != iFin; iIdx += iSens )
 {
 iBcl = llList2Integer( lSortPrims, iIdx );
 lElem = [ PRIM_SIZE, llList2Vector( lSizes, iIdx ) ];
 if( iBcl != iFirst )
 {
 vPos = llList2Vector( lPos, iIdx );
 lElem += [ PRIM_POSITION, vPos ];
 }
 llSetLinkPrimitiveParamsFast( iBcl, lElem );
 llSetLinkPrimitiveParamsFast( iBcl, lElem );
 llSetLinkPrimitiveParamsFast( iBcl, lElem );
 }
 ControlBuild( FALSE );
 }
 while( iError && --iNbPasses );
 if( iError )
 llOwnerSay( "Sorry, the build is broken and can't be repaired." );
}
// Function to store size and relative positions of each prim after a successfull resizing
SaveSizePos()
{
 Booster();
 fFactor = 1.0;
 lSizes = [];
 lPos = [];
 for( iIdx = 0; iIdx != iNumberOfPrims; iIdx++ )
 {
 iBcl = llList2Integer( lSortPrims, iIdx );
 GetSizePos();
 lSizes += [ vSize ];
 lPos += [ vPos ];
 }
}
// Function to resize the build
Resize( integer iMess )
{
// Apply factor of resizing to the min and max size found in the build
 fMin *= fFactor;
 fMax *= fFactor;
 sPct = "done";
 if( fFactor < 1.0 )
 {
// If resize is to decrease the size, we start whith the most distant prims from the root
 iDeb = llGetListLength( lSortPrims ) - 1;
 iFin = -1;
 iSens = -1;
 }
 else
 {
// If resize is to increase the size, we start whith the closer prims from the root
 iDeb = 0;
 iFin = llGetListLength( lSortPrims );
 iSens = 1;
 }
 iError = FALSE;
 if( fFactor < 0.5 )
// if decrease is more than a factor 2, we start by changing only relative positions
 ChangePos( FALSE );
 else if( fFactor > 2.0 )
// if increase is more than a factor 2, we start by changing only sizes
 ChangeSize( FALSE );
 else
// if factor is less or equal than 2, resize is both size and position
 ChangeSizePos();
 if( ! iError )
 {
 if( fFactor < 0.5 )
// Changing positions is successfull, we change positions
 ChangeSize( TRUE );
 else if( fFactor > 2.0 )
// Changing sizes is successfull, we change sizes
 ChangePos( TRUE );
 }
 if( ! iError )
 ControlBuild( TRUE );
 if( iError )
// Restore the last good size after error
 GoBackToGoodSize();
 else
 {
// Save the sizes and relative positions of each prim
 SaveSizePos();
 if( fMax == 10.0 && ! iAllowResizeHugePrims )
 {
 iNoMoreMax = TRUE;
 fLimiteMax = fMax;
 }
 }
 if( fMax > fLimiteMax )
// New max size found
 fLimiteMax = fMax;
// Start countdown for CHANGED_SCALE event
 llResetTime();
 if( iMess )
 {
// Inform user the resize is finished and call back the menu
 llOwnerSay( "Resize " + sPct + "." );
 Menu();
 }
}
AlreadyAt( integer iMess, string sMess )
{
 if( iMess )
 {
 llOwnerSay( "Already at " + sMess + " size." );
 Menu();
 }
}
// Function to resize to the minimum size
MinimumSize( integer iMess )
{
 if( ( fFactor = 0.01 / fMin ) != 1.0 )
 {
 if( iMess )
 {
 sPct = (string)llRound( ( fFactor - 1.0 ) * 100.0 );
 if( fFactor > 1.0 )
 sPct = "+" + sPct;
 llOwnerSay( "Minimum size (" + sPct + "%)..." );
 }
 Resize( iMess );
 }
 else
 AlreadyAt( iMess, "minimum" );
}
// Function to resize to the maximum size
MaximumSize( integer iMess )
{
 if( ( fFactor = fLimiteMax / fMax ) != 1.0 )
 {
 if( iMess )
 {
 sPct = (string)llRound( ( fFactor - 1.0 ) * 100.0 );
 if( fFactor > 1.0 )
 sPct = "+" + sPct;
 llOwnerSay( "Maximum size (" + sPct + "%)..." );
 }
 Resize( iMess );
 }
 else
 AlreadyAt( iMess, "maximum" );
}
// Function to resize to the default size
DefaultSize( integer iMess )
{
 vSize = llList2Vector( llGetLinkPrimitiveParams( iFirst, [ PRIM_SIZE ] ), 0 );
 if( ( fFactor = fDefault / vSize.x ) != 1.0 )
 {
 if( iMess )
 {
 sPct = (string)llRound( ( fFactor - 1.0 ) * 100.0 );
 if( fFactor > 1.0 )
 sPct = "+" + sPct;
 llOwnerSay( "Default size (" + sPct + "%)..." );
 }
 Resize( iMess );
 }
 else
 AlreadyAt( iMess, "default" );
}
// Close the menu
FinMenu( integer iAlert )
{
 iMenuOn = FALSE;
 llSetTimerEvent( 0.0 );
 llListenRemove( iEcouteMenu );
 if( iAlert )
 llOwnerSay( "Menu timeout." );
}
// Main menu
Menu()
{
 llSetTimerEvent( 30.0 );
 llDialog( llGetOwner(),
 "Resizer action :\n" +
 "Quit : Leave this menu.\n" +
 "Options : Current size becomes default.\n" +
 ">> : Next set of percentages.\n" +
 "Min : Resize to minimum size.\n" +
 "Default : Return to initial size.\n" +
 "Max : Resize to maximum size.",
 [ "Quit", "Options", ">>",
 "-" + sPctM1 + "%", "Min", "+" + sPctP1 + "%",
 "-" + sPctM2 + "%", "Default", "+" + sPctP2 + "%",
 "-" + sPctM3 + "%", "Max", "+" + sPctP3 + "%" ],
 iCanalMenu );
}
// Function to return min or max element of vSize vector
float MinMaxVal( integer iOperation )
{
 return( llListStatistics( iOperation, [ vSize.x, vSize.y, vSize.z ] ) );
}
// Initialisation of the script
init()
{
 Booster();
 iNumberOfPrims = llGetNumberOfPrims();
 iFirst = (integer)( iNumberOfPrims > 1 );
 iLast = iNumberOfPrims - (integer)( iNumberOfPrims == 1 );
 llOwnerSay( "Searching min/max prim size..." );
 fMin = 10.0;
 fMax = 0.01;
 fFactor = 1.0;
 for( iBcl = iFirst; ( fMax <= 10.0 || iAllowResizeHugePrims ) && iBcl <= iLast; iBcl++ )
 {
 GetSizePos();
 if( iBcl == iFirst )
 {
 fDefault = vSize.x;
 lElem = [ 0.0, iFirst ];
 }
 else
 lElem += [ llVecDist( ZERO_VECTOR, vPos ), iBcl ];
 fTmp = MinMaxVal( LIST_STAT_MIN );
 if( fTmp < fMin )
 fMin = fTmp;
 fTmp = MinMaxVal( LIST_STAT_MAX );
 if( fTmp > fMax )
 fMax = fTmp;
 }
 if( fMax > 10.0 && ! iAllowResizeHugePrims )
 {
 iHugeUsed = TRUE;
 llOwnerSay( "Script not active, object uses huge prim." );
 }
 else
 {
 llOwnerSay( "Size range : " + (string)fMin + " -> " + (string)fMax );
 iNoMoreMax = FALSE;
 iHugeUsed = FALSE;
 llOwnerSay( "Sorting prims..." );
 lElem = llListSort( lElem, 2, TRUE );
 lSortPrims = [];
 for( iBcl = 1; iBcl < llGetListLength( lElem ); iBcl += 2 )
 lSortPrims += [ llList2Integer( lElem, iBcl ) ];
 llOwnerSay( (string)iNumberOfPrims + " prim" + llList2String( [ "", "s" ], (integer)(iNumberOfPrims > 1) ) + " sorted." );
 fLimiteMax = llListStatistics( LIST_STAT_MAX, [ 10.0, fMax ] );
 llOwnerSay( "Storing size/pos of each prim..." );
 SaveSizePos();
 }
 llOwnerSay( "Init. complete." );
}
default
{
 state_entry()
 {
 if( iAllowResizeHugePrims < 0 )
 iAllowResizeHugePrims = (integer)( llSubStringIndex( llGetSimulatorHostname(), ".lindenlab.com" ) < 0 );
 init();
 llListen( iCanalComm, "", NULL_KEY, "" );
 }
 changed( integer iChange )
 {
 if( ( iChange & CHANGED_LINK ) ||
 ( ( iChange & CHANGED_SCALE ) &&
 llGetTime() > 5.0 / llList2Float( [ llGetRegionTimeDilation(), 0.01 ],
 (integer)( llGetRegionTimeDilation() < 0.01 ) ) ) )
 init();
 }
 listen( integer iChannel, string sName, key kId, string sMess )
 {
 if( iChannel == iCanalMenu )
 {
 llSetTimerEvent( 0.0 );
 if( sMess == ">>" )
 {
 if( (++iCurrentMenu) == 3 )
 iCurrentMenu = 0;
 if( ! iCurrentMenu )
 {
 sPctM1 = "1";
 sPctM2 = "2";
 sPctM3 = "5";
 sPctP1 = "1";
 sPctP2 = "2";
 sPctP3 = "5";
 }
 else if( iCurrentMenu == 1 )
 {
 sPctM1 = "10";
 sPctM2 = "25";
 sPctM3 = "50";
 sPctP1 = "10";
 sPctP2 = "25";
 sPctP3 = "50";
 }
 else
 {
 sPctM1 = "75";
 sPctM2 = "85";
 sPctM3 = "95";
 sPctP1 = "75";
 sPctP2 = "100";
 sPctP3 = "200";
 }
 Menu();
 }
 else if( sMess == "Options" || sMess == " " )
 {
 llSetTimerEvent( 30.0 );
 llDialog( llGetOwner(),
 "\nResizer options :\n \n" +
 "Quit : Leave this menu.\n" +
 "BACK : To main menu.\n" +
 "Set default : Current size is default.\n" +
 "Remove : Remove the script.",
 [ "Quit", " ", "BACK",
 "Set default", " ", "Remove" ],
 iCanalMenu );
 }
 else if( sMess == "BACK" )
 Menu();
 else if( sMess == "Set default" )
 {
 vSize = llList2Vector( llGetLinkPrimitiveParams( iFirst, [ PRIM_SIZE ] ), 0 );
 fDefault = vSize.x;
 if( llGetAttached() )
 llSay( iCanalComm, (string)llGetOwner() + "|Default|" + (string)fDefault );
 llOwnerSay( "This size is now the default size." );
 Menu();
 }
 else if( sMess == "Remove" )
 {
 llSetTimerEvent( 30.0 );
 llDialog( llGetOwner(),
 "\nSure to remove the script from this object ?",
 [ "Yes", "No" ],
 iCanalMenu );
 }
 else if( sMess == "Default" )
 DefaultSize( TRUE );
 else if( sMess == "Min" )
 MinimumSize( TRUE );
 else if( sMess == "Max" )
 MaximumSize( TRUE );
 else if( ( iBcl = llListFindList( [ "+", "-" ], [ llGetSubString( sMess, 0, 0 ) ] ) ) >= 0 )
 {
 fFactor = 1.0 + (float)llGetSubString( sMess, 0, -2 ) / 100.0;
 fTmp = llList2Float( [ llList2Float( [ 10.0, 10000.0 ], iAllowResizeHugePrims ), fLimiteMax ], iNoMoreMax );
 if( fMin * fFactor < 0.01 )
 fFactor = 0.01 / fMin;
 else if( fMax * fFactor > fTmp )
 fFactor = fTmp / fMax;
 if( fMin * fFactor >= 0.01 && fMax * fFactor <= fTmp && llRound( fFactor * 100.0 ) != 100 )
 {
 sPct = (string)llRound( ( fFactor - 1.0 ) * 100.0 ) + "%";
 if( fFactor > 1.0 )
 sPct = "+" + sPct;
 llOwnerSay( llList2String( [ "Increas", "Reduc" ], iBcl ) + "ing size : " +
 sPct + llList2String( [ " (" + sMess + " asked)", "" ], (integer)(sMess == sPct) ) + "..." );
 if( llGetAttached() )
 llSay( iCanalComm, (string)llGetOwner() + "|Factor|" + (string)fFactor );
 Resize( TRUE );
 }
 else
 {
 llOwnerSay( "Out of size range." );
 Menu();
 }
 }
 else
 {
 FinMenu( FALSE );
 if( sMess == "Yes" )
 {
 if( llGetAttached() )
 llSay( iCanalComm, (string)llGetOwner() + "|Remove" );
 llRemoveInventory( llGetScriptName() );
 }
 }
 }
 else if( llGetAttached() && sName != llGetObjectName() )
 {
 lElem = llParseString2List( sName, [ " " ], [ "" ] );
 if( llGetListLength( lElem ) < 2 )
 return;
 lName = llParseString2List( llGetObjectName(), [ " " ], [ "" ] );
 if( llGetListLength( lName ) < 2 )
 return;
 if( llDumpList2String( llList2List( lElem, 0, -2 ), " " ) !=
 llDumpList2String( llList2List( lName, 0, -2 ), " " ) )
 return;
 lElem = llParseString2List( sMess, [ "|" ], [ "" ] );
 if( llList2String( lElem, 0 ) == (string)llGetOwner() )
 {
 if( llList2String( lElem, 1 ) == "Remove" )
 llRemoveInventory( llGetScriptName() );
 else if( llList2String( lElem, 1 ) == "Factor" )
 {
 fFactor = llList2Float( lElem, 2 );
 Resize( FALSE );
 llResetTime();
 }
 else if( llList2String( lElem, 1 ) == "Min" )
 MinimumSize( FALSE );
 else if( llList2String( lElem, 1 ) == "Max" )
 MaximumSize( FALSE );
 else if( llList2String( lElem, 1 ) == "Default" )
 {
 if( llGetListLength( lElem ) == 2 )
 DefaultSize( FALSE );
 else
 fDefault = llList2Float( lElem, 2 );
 }
 }
 }
 }
 timer()
 {
 FinMenu( TRUE );
 }
 touch_start( integer iNum )
 {
 if( llDetectedKey( 0 ) == llGetOwner() && ! iMenuOn && ! iHugeUsed )
 {
//llOwnerSay( (string)llGetFreeMemory() );
 iMenuOn = TRUE;
 iCanalMenu = iCanalComm - 10 - (integer)llFrand( 124578 );
 iEcouteMenu = llListen( iCanalMenu, "", llGetOwner(), "" );
 Menu();
 }
 }
}