Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 184 files). Show all
Unified · Split
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | #include <AudioInjector.h> | 20 | #include <AudioInjector.h> |
| 21 | #include <AudioRingBuffer.h> | 21 | #include <AudioRingBuffer.h> |
| 22 | #include <AvatarData.h> | 22 | #include <AvatarData.h> |
| 23 | #include <Bitstream.h> | ||
| 23 | #include <CollisionInfo.h> | 24 | #include <CollisionInfo.h> |
| 24 | #include <EntityScriptingInterface.h> | 25 | #include <EntityScriptingInterface.h> |
| 25 | #include <NetworkAccessManager.h> | 26 | #include <NetworkAccessManager.h> |
| @@ -71,6 +72,14 @@ void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) { · 45 unmodified lines | |||
| 71 | out = qobject_cast<AudioInjector*>(object.toQObject()); | 72 | out = qobject_cast<AudioInjector*>(object.toQObject()); |
| 72 | } | 73 | } |
| 73 | 74 | ||
| 75 | QScriptValue injectorToScriptValueInputController(QScriptEngine *engine, AbstractInputController* const &in) { | ||
| 76 | return engine->newQObject(in); | ||
| 77 | } | ||
| 78 | |||
| 79 | void injectorFromScriptValueInputController(const QScriptValue &object, AbstractInputController* &out) { | ||
| 80 | out = qobject_cast<AbstractInputController*>(object.toQObject()); | ||
| 81 | } | ||
| 82 | |||
| 74 | ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, | 83 | ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, |
| 75 | AbstractControllerScriptingInterface* controllerScriptingInterface) : | 84 | AbstractControllerScriptingInterface* controllerScriptingInterface) : |
| 76 | 85 | ||
| @@ -78,7 +87,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam · 1 unmodified line | |||
| 78 | _isFinished(false), | 87 | _isFinished(false), |
| 79 | _isRunning(false), | 88 | _isRunning(false), |
| 80 | _isInitialized(false), | 89 | _isInitialized(false), |
| 81 | _engine(), | ||
| 82 | _isAvatar(false), | 90 | _isAvatar(false), |
| 83 | _avatarIdentityTimer(NULL), | 91 | _avatarIdentityTimer(NULL), |
| 84 | _avatarBillboardTimer(NULL), | 92 | _avatarBillboardTimer(NULL), |
| @@ -104,7 +112,6 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, · 19 unmodified lines | |||
| 104 | _isFinished(false), | 112 | _isFinished(false), |
| 105 | _isRunning(false), | 113 | _isRunning(false), |
| 106 | _isInitialized(false), | 114 | _isInitialized(false), |
| 107 | _engine(), | ||
| 108 | _isAvatar(false), | 115 | _isAvatar(false), |
| 109 | _avatarIdentityTimer(NULL), | 116 | _avatarIdentityTimer(NULL), |
| 110 | _avatarBillboardTimer(NULL), | 117 | _avatarBillboardTimer(NULL), |
| @@ -185,7 +192,7 @@ void ScriptEngine::setAvatarData(AvatarData* avatarData, const QString& objectNa · 74 unmodified lines | |||
| 185 | _avatarData = avatarData; | 192 | _avatarData = avatarData; |
| 186 | 193 | ||
| 187 | // remove the old Avatar property, if it exists | 194 | // remove the old Avatar property, if it exists |
| 188 | _engine.globalObject().setProperty(objectName, QScriptValue()); | 195 | globalObject().setProperty(objectName, QScriptValue()); |
| 189 | 196 | ||
| 190 | // give the script engine the new Avatar script property | 197 | // give the script engine the new Avatar script property |
| 191 | registerGlobalObject(objectName, _avatarData); | 198 | registerGlobalObject(objectName, _avatarData); |
| @@ -193,7 +200,7 @@ void ScriptEngine::setAvatarData(AvatarData* avatarData, const QString& objectNa · 1 unmodified line | |||
| 193 | 200 | ||
| 194 | void ScriptEngine::setAvatarHashMap(AvatarHashMap* avatarHashMap, const QString& objectName) { | 201 | void ScriptEngine::setAvatarHashMap(AvatarHashMap* avatarHashMap, const QString& objectName) { |
| 195 | // remove the old Avatar property, if it exists | 202 | // remove the old Avatar property, if it exists |
| 196 | _engine.globalObject().setProperty(objectName, QScriptValue()); | 203 | globalObject().setProperty(objectName, QScriptValue()); |
| 197 | 204 | ||
| 198 | // give the script engine the new avatar hash map | 205 | // give the script engine the new avatar hash map |
| 199 | registerGlobalObject(objectName, avatarHashMap); | 206 | registerGlobalObject(objectName, avatarHashMap); |
| @@ -222,46 +229,55 @@ void ScriptEngine::init() { · 22 unmodified lines | |||
| 222 | _particlesScriptingInterface.init(); | 229 | _particlesScriptingInterface.init(); |
| 223 | 230 | ||
| 224 | // register various meta-types | 231 | // register various meta-types |
| 225 | registerMetaTypes(&_engine); | 232 | registerMetaTypes(this); |
| 226 | registerMIDIMetaTypes(&_engine); | 233 | registerMIDIMetaTypes(this); |
| 227 | registerVoxelMetaTypes(&_engine); | 234 | registerVoxelMetaTypes(this); |
| 228 | registerEventTypes(&_engine); | 235 | registerEventTypes(this); |
| 229 | registerMenuItemProperties(&_engine); | 236 | registerMenuItemProperties(this); |
| 230 | registerAnimationTypes(&_engine); | 237 | registerAnimationTypes(this); |
| 231 | registerAvatarTypes(&_engine); | 238 | registerAvatarTypes(this); |
| 232 | 239 | Bitstream::registerTypes(this); | |
| 233 | qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); | 240 | |
| 234 | qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue); | 241 | qScriptRegisterMetaType(this, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); |
| 235 | qScriptRegisterSequenceMetaType<QVector<ParticleID> >(&_engine); | 242 | qScriptRegisterMetaType(this, ParticleIDtoScriptValue, ParticleIDfromScriptValue); |
| 236 | 243 | qScriptRegisterSequenceMetaType<QVector<ParticleID> >(this); | |
| 237 | qScriptRegisterMetaType(&_engine, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue); | 244 | |
| 238 | qScriptRegisterMetaType(&_engine, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); | 245 | /** |
| 239 | qScriptRegisterMetaType(&_engine, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue); | 246 | qScriptRegisterMetaType(this, ModelItemPropertiesToScriptValue, ModelItemPropertiesFromScriptValue); |
| 240 | qScriptRegisterSequenceMetaType<QVector<EntityItemID> >(&_engine); | 247 | qScriptRegisterMetaType(this, ModelItemIDtoScriptValue, ModelItemIDfromScriptValue); |
| 241 | 248 | qScriptRegisterMetaType(this, RayToModelIntersectionResultToScriptValue, RayToModelIntersectionResultFromScriptValue); | |
| 242 | qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(&_engine); | 249 | qScriptRegisterSequenceMetaType<QVector<ModelItemID> >(this); |
| 243 | qScriptRegisterSequenceMetaType<QVector<glm::quat> >(&_engine); | 250 | **/ |
| 244 | qScriptRegisterSequenceMetaType<QVector<QString> >(&_engine); | 251 | |
| 245 | 252 | qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue); | |
| 246 | QScriptValue xmlHttpRequestConstructorValue = _engine.newFunction(XMLHttpRequestClass::constructor); | 253 | qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); |
| 247 | _engine.globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); | 254 | qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue); |
| 248 | 255 | qScriptRegisterSequenceMetaType<QVector<EntityItemID> >(this); | |
| 249 | QScriptValue printConstructorValue = _engine.newFunction(debugPrint); | 256 | |
| 250 | _engine.globalObject().setProperty("print", printConstructorValue); | 257 | qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(this); |
| 251 | 258 | qScriptRegisterSequenceMetaType<QVector<glm::quat> >(this); | |
| 252 | QScriptValue soundConstructorValue = _engine.newFunction(soundConstructor); | 259 | qScriptRegisterSequenceMetaType<QVector<QString> >(this); |
| 253 | QScriptValue soundMetaObject = _engine.newQMetaObject(&Sound::staticMetaObject, soundConstructorValue); | 260 | |
| 254 | _engine.globalObject().setProperty("Sound", soundMetaObject); | 261 | QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor); |
| 255 | 262 | globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); | |
| 256 | QScriptValue injectionOptionValue = _engine.scriptValueFromQMetaObject<AudioInjectorOptions>(); | 263 | |
| 257 | _engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue); | 264 | QScriptValue printConstructorValue = newFunction(debugPrint); |
| 258 | 265 | globalObject().setProperty("print", printConstructorValue); | |
| 259 | QScriptValue localVoxelsValue = _engine.scriptValueFromQMetaObject<LocalVoxels>(); | 266 | |
| 260 | _engine.globalObject().setProperty("LocalVoxels", localVoxelsValue); | 267 | QScriptValue soundConstructorValue = newFunction(soundConstructor); |
| 268 | QScriptValue soundMetaObject = newQMetaObject(&Sound::staticMetaObject, soundConstructorValue); | ||
| 269 | globalObject().setProperty("Sound", soundMetaObject); | ||
| 270 | |||
| 271 | QScriptValue injectionOptionValue = scriptValueFromQMetaObject<AudioInjectorOptions>(); | ||
| 272 | globalObject().setProperty("AudioInjectionOptions", injectionOptionValue); | ||
| 273 | |||
| 274 | QScriptValue localVoxelsValue = scriptValueFromQMetaObject<LocalVoxels>(); | ||
| 275 | globalObject().setProperty("LocalVoxels", localVoxelsValue); | ||
| 261 | 276 | ||
| 262 | qScriptRegisterMetaType(&_engine, injectorToScriptValue, injectorFromScriptValue); | 277 | qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); |
| 278 | qScriptRegisterMetaType( this, injectorToScriptValueInputController, injectorFromScriptValueInputController); | ||
| 263 | 279 | ||
| 264 | qScriptRegisterMetaType(&_engine, animationDetailsToScriptValue, animationDetailsFromScriptValue); | 280 | qScriptRegisterMetaType(this, animationDetailsToScriptValue, animationDetailsFromScriptValue); |
| 265 | 281 | ||
| 266 | registerGlobalObject("Script", this); | 282 | registerGlobalObject("Script", this); |
| 267 | registerGlobalObject("Audio", &_audioScriptingInterface); | 283 | registerGlobalObject("Audio", &_audioScriptingInterface); |
| @@ -276,15 +292,14 @@ void ScriptEngine::init() { · 8 unmodified lines | |||
| 276 | registerGlobalObject("Voxels", &_voxelsScriptingInterface); | 292 | registerGlobalObject("Voxels", &_voxelsScriptingInterface); |
| 277 | 293 | ||
| 278 | // constants | 294 | // constants |
| 279 | QScriptValue globalObject = _engine.globalObject(); | 295 | globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); |
| 280 | globalObject.setProperty("TREE_SCALE", _engine.newVariant(QVariant(TREE_SCALE))); | 296 | globalObject().setProperty("COLLISION_GROUP_ENVIRONMENT", newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT))); |
| 281 | globalObject.setProperty("COLLISION_GROUP_ENVIRONMENT", _engine.newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT))); | 297 | globalObject().setProperty("COLLISION_GROUP_AVATARS", newVariant(QVariant(COLLISION_GROUP_AVATARS))); |
| 282 | globalObject.setProperty("COLLISION_GROUP_AVATARS", _engine.newVariant(QVariant(COLLISION_GROUP_AVATARS))); | 298 | globalObject().setProperty("COLLISION_GROUP_VOXELS", newVariant(QVariant(COLLISION_GROUP_VOXELS))); |
| 283 | globalObject.setProperty("COLLISION_GROUP_VOXELS", _engine.newVariant(QVariant(COLLISION_GROUP_VOXELS))); | 299 | globalObject().setProperty("COLLISION_GROUP_PARTICLES", newVariant(QVariant(COLLISION_GROUP_PARTICLES))); |
| 284 | globalObject.setProperty("COLLISION_GROUP_PARTICLES", _engine.newVariant(QVariant(COLLISION_GROUP_PARTICLES))); | ||
| 285 | 300 | ||
| 286 | globalObject.setProperty("AVATAR_MOTION_OBEY_LOCAL_GRAVITY", _engine.newVariant(QVariant(AVATAR_MOTION_OBEY_LOCAL_GRAVITY))); | 301 | globalObject().setProperty("AVATAR_MOTION_OBEY_LOCAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_LOCAL_GRAVITY))); |
| 287 | globalObject.setProperty("AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY", _engine.newVariant(QVariant(AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY))); | 302 | globalObject().setProperty("AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY))); |
| 288 | 303 | ||
| 289 | // let the VoxelPacketSender know how frequently we plan to call it | 304 | // let the VoxelPacketSender know how frequently we plan to call it |
| 290 | _voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(SCRIPT_DATA_CALLBACK_USECS); | 305 | _voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(SCRIPT_DATA_CALLBACK_USECS); |
| @@ -293,8 +308,8 @@ void ScriptEngine::init() { · 2 unmodified lines | |||
| 293 | 308 | ||
| 294 | QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { | 309 | QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { |
| 295 | if (object) { | 310 | if (object) { |
| 296 | QScriptValue value = _engine.newQObject(object); | 311 | QScriptValue value = newQObject(object); |
| 297 | _engine.globalObject().setProperty(name, value); | 312 | globalObject().setProperty(name, value); |
| 298 | return value; | 313 | return value; |
| 299 | } | 314 | } |
| 300 | return QScriptValue::NullValue; | 315 | return QScriptValue::NullValue; |
| @@ -302,15 +317,15 @@ QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* ob · 1 unmodified line | |||
| 302 | 317 | ||
| 303 | void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, | 318 | void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, |
| 304 | QScriptEngine::FunctionSignature setter, QScriptValue object) { | 319 | QScriptEngine::FunctionSignature setter, QScriptValue object) { |
| 305 | QScriptValue setterFunction = _engine.newFunction(setter, 1); | 320 | QScriptValue setterFunction = newFunction(setter, 1); |
| 306 | QScriptValue getterFunction = _engine.newFunction(getter); | 321 | QScriptValue getterFunction = newFunction(getter); |
| 307 | 322 | ||
| 308 | if (!object.isNull()) { | 323 | if (!object.isNull()) { |
| 309 | object.setProperty(name, setterFunction, QScriptValue::PropertySetter); | 324 | object.setProperty(name, setterFunction, QScriptValue::PropertySetter); |
| 310 | object.setProperty(name, getterFunction, QScriptValue::PropertyGetter); | 325 | object.setProperty(name, getterFunction, QScriptValue::PropertyGetter); |
| 311 | } else { | 326 | } else { |
| 312 | _engine.globalObject().setProperty(name, setterFunction, QScriptValue::PropertySetter); | 327 | globalObject().setProperty(name, setterFunction, QScriptValue::PropertySetter); |
| 313 | _engine.globalObject().setProperty(name, getterFunction, QScriptValue::PropertyGetter); | 328 | globalObject().setProperty(name, getterFunction, QScriptValue::PropertyGetter); |
| 314 | } | 329 | } |
| 315 | } | 330 | } |
| 316 | 331 | ||
| @@ -319,25 +334,24 @@ void ScriptEngine::evaluate() { · 2 unmodified lines | |||
| 319 | init(); | 334 | init(); |
| 320 | } | 335 | } |
| 321 | 336 | ||
| 322 | QScriptValue result = _engine.evaluate(_scriptContents); | 337 | QScriptValue result = evaluate(_scriptContents); |
| 323 | 338 | ||
| 324 | if (_engine.hasUncaughtException()) { | 339 | if (hasUncaughtException()) { |
| 325 | int line = _engine.uncaughtExceptionLineNumber(); | 340 | int line = uncaughtExceptionLineNumber(); |
| 326 | qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); | 341 | qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); |
| 327 | emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); | 342 | emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); |
| 328 | _engine.clearExceptions(); | 343 | clearExceptions(); |
| 329 | } | 344 | } |
| 330 | } | 345 | } |
| 331 | 346 | ||
| 332 | QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) { | 347 | QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) { |
| 333 | QScriptValue result = _engine.evaluate(program, fileName, lineNumber); | 348 | QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber); |
| 334 | bool hasUncaughtException = _engine.hasUncaughtException(); | 349 | if (hasUncaughtException()) { |
| 335 | if (hasUncaughtException) { | 350 | int line = uncaughtExceptionLineNumber(); |
| 336 | int line = _engine.uncaughtExceptionLineNumber(); | ||
| 337 | qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ": " << result.toString(); | 351 | qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ": " << result.toString(); |
| 338 | } | 352 | } |
| 339 | emit evaluationFinished(result, hasUncaughtException); | 353 | emit evaluationFinished(result, hasUncaughtException()); |
| 340 | _engine.clearExceptions(); | 354 | clearExceptions(); |
| 341 | return result; | 355 | return result; |
| 342 | } | 356 | } |
| 343 | 357 | ||
| @@ -361,12 +375,12 @@ void ScriptEngine::run() { · 17 unmodified lines | |||
| 361 | _isFinished = false; | 375 | _isFinished = false; |
| 362 | emit runningStateChanged(); | 376 | emit runningStateChanged(); |
| 363 | 377 | ||
| 364 | QScriptValue result = _engine.evaluate(_scriptContents); | 378 | QScriptValue result = evaluate(_scriptContents); |
| 365 | if (_engine.hasUncaughtException()) { | 379 | if (hasUncaughtException()) { |
| 366 | int line = _engine.uncaughtExceptionLineNumber(); | 380 | int line = uncaughtExceptionLineNumber(); |
| 367 | qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); | 381 | qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); |
| 368 | emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); | 382 | emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); |
| 369 | _engine.clearExceptions(); | 383 | clearExceptions(); |
| 370 | } | 384 | } |
| 371 | 385 | ||
| 372 | QElapsedTimer startTime; | 386 | QElapsedTimer startTime; |
| @@ -521,11 +535,11 @@ void ScriptEngine::run() { · 148 unmodified lines | |||
| 521 | qint64 now = usecTimestampNow(); | 535 | qint64 now = usecTimestampNow(); |
| 522 | float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; | 536 | float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; |
| 523 | 537 | ||
| 524 | if (_engine.hasUncaughtException()) { | 538 | if (hasUncaughtException()) { |
| 525 | int line = _engine.uncaughtExceptionLineNumber(); | 539 | int line = uncaughtExceptionLineNumber(); |
| 526 | qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << _engine.uncaughtException().toString(); | 540 | qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << uncaughtException().toString(); |
| 527 | emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + _engine.uncaughtException().toString()); | 541 | emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + uncaughtException().toString()); |
| 528 | _engine.clearExceptions(); | 542 | clearExceptions(); |
| 529 | } | 543 | } |
| 530 | 544 | ||
| 531 | emit update(deltaTime); | 545 | emit update(deltaTime); |
| @@ -683,12 +697,12 @@ void ScriptEngine::include(const QString& includeFile) { · 151 unmodified lines | |||
| 683 | } | 697 | } |
| 684 | } | 698 | } |
| 685 | 699 | ||
| 686 | QScriptValue result = _engine.evaluate(includeContents); | 700 | QScriptValue result = evaluate(includeContents); |
| 687 | if (_engine.hasUncaughtException()) { | 701 | if (hasUncaughtException()) { |
| 688 | int line = _engine.uncaughtExceptionLineNumber(); | 702 | int line = uncaughtExceptionLineNumber(); |
| 689 | qDebug() << "Uncaught exception at (" << includeFile << ") line" << line << ":" << result.toString(); | 703 | qDebug() << "Uncaught exception at (" << includeFile << ") line" << line << ":" << result.toString(); |
| 690 | emit errorMessage("Uncaught exception at (" + includeFile + ") line" + QString::number(line) + ":" + result.toString()); | 704 | emit errorMessage("Uncaught exception at (" + includeFile + ") line" + QString::number(line) + ":" + result.toString()); |
| 691 | _engine.clearExceptions(); | 705 | clearExceptions(); |
| 692 | } | 706 | } |
| 693 | } | 707 | } |
| 694 | 708 | ||