aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs
diff options
context:
space:
mode:
authoronefang2019-05-19 21:24:15 +1000
committeronefang2019-05-19 21:24:15 +1000
commit5e4d6cab00cb29cd088ab7b62ab13aff103b64cb (patch)
treea9fbc62df9eb2d1d9ba2698d8552eae71eca20d8 /OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs
parentAdd a build script. (diff)
downloadopensim-SC-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.zip
opensim-SC-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.gz
opensim-SC-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.bz2
opensim-SC-5e4d6cab00cb29cd088ab7b62ab13aff103b64cb.tar.xz
Dump OpenSim 0.9.0.1 into it's own branch.
Diffstat (limited to 'OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs')
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs311
1 files changed, 218 insertions, 93 deletions
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs
index c04ff58..2fa98b5 100644
--- a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs
+++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs
@@ -43,7 +43,8 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
43 Unknown = 0, 43 Unknown = 0,
44 Agent = 1, 44 Agent = 1,
45 Prim = 2, 45 Prim = 2,
46 Ground = 3 46 Ground = 3,
47 Water = 4
47 } 48 }
48 49
49 public enum PIDHoverType 50 public enum PIDHoverType
@@ -54,20 +55,54 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
54 Absolute 55 Absolute
55 } 56 }
56 57
58 public struct CameraData
59 {
60 public Quaternion CameraRotation;
61 public Vector3 CameraAtAxis;
62 public bool MouseLook;
63 public bool Valid;
64 }
65
57 public struct ContactPoint 66 public struct ContactPoint
58 { 67 {
59 public Vector3 Position; 68 public Vector3 Position;
60 public Vector3 SurfaceNormal; 69 public Vector3 SurfaceNormal;
61 public float PenetrationDepth; 70 public float PenetrationDepth;
71 public float RelativeSpeed;
72 public bool CharacterFeet;
62 73
63 public ContactPoint(Vector3 position, Vector3 surfaceNormal, float penetrationDepth) 74 public ContactPoint(Vector3 position, Vector3 surfaceNormal, float penetrationDepth)
64 { 75 {
65 Position = position; 76 Position = position;
66 SurfaceNormal = surfaceNormal; 77 SurfaceNormal = surfaceNormal;
67 PenetrationDepth = penetrationDepth; 78 PenetrationDepth = penetrationDepth;
79 RelativeSpeed = 0f; // for now let this one be set explicity
80 CharacterFeet = true; // keep other plugins work as before
81 }
82
83 public ContactPoint(Vector3 position, Vector3 surfaceNormal, float penetrationDepth, bool feet)
84 {
85 Position = position;
86 SurfaceNormal = surfaceNormal;
87 PenetrationDepth = penetrationDepth;
88 RelativeSpeed = 0f; // for now let this one be set explicity
89 CharacterFeet = feet; // keep other plugins work as before
68 } 90 }
69 } 91 }
70 92
93 public struct ContactData
94 {
95 public float mu;
96 public float bounce;
97 public bool softcolide;
98
99 public ContactData(float _mu, float _bounce, bool _softcolide)
100 {
101 mu = _mu;
102 bounce = _bounce;
103 softcolide = _softcolide;
104 }
105 }
71 /// <summary> 106 /// <summary>
72 /// Used to pass collision information to OnCollisionUpdate listeners. 107 /// Used to pass collision information to OnCollisionUpdate listeners.
73 /// </summary> 108 /// </summary>
@@ -100,8 +135,19 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
100 } 135 }
101 else 136 else
102 { 137 {
138 float lastVel = m_objCollisionList[localID].RelativeSpeed;
103 if (m_objCollisionList[localID].PenetrationDepth < contact.PenetrationDepth) 139 if (m_objCollisionList[localID].PenetrationDepth < contact.PenetrationDepth)
140 {
141 if(Math.Abs(lastVel) > Math.Abs(contact.RelativeSpeed))
142 contact.RelativeSpeed = lastVel;
104 m_objCollisionList[localID] = contact; 143 m_objCollisionList[localID] = contact;
144 }
145 else if(Math.Abs(lastVel) < Math.Abs(contact.RelativeSpeed))
146 {
147 ContactPoint tmp = m_objCollisionList[localID];
148 tmp.RelativeSpeed = contact.RelativeSpeed;
149 m_objCollisionList[localID] = tmp;
150 }
105 } 151 }
106 } 152 }
107 153
@@ -121,13 +167,15 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
121 public delegate void RequestTerseUpdate(); 167 public delegate void RequestTerseUpdate();
122 public delegate void CollisionUpdate(EventArgs e); 168 public delegate void CollisionUpdate(EventArgs e);
123 public delegate void OutOfBounds(Vector3 pos); 169 public delegate void OutOfBounds(Vector3 pos);
170 public delegate CameraData GetCameraData();
124 171
125// disable warning: public events 172 // disable warning: public events
126#pragma warning disable 67 173#pragma warning disable 67
127 public event PositionUpdate OnPositionUpdate; 174 public event PositionUpdate OnPositionUpdate;
128 public event VelocityUpdate OnVelocityUpdate; 175 public event VelocityUpdate OnVelocityUpdate;
129 public event OrientationUpdate OnOrientationUpdate; 176 public event OrientationUpdate OnOrientationUpdate;
130 public event RequestTerseUpdate OnRequestTerseUpdate; 177 public event RequestTerseUpdate OnRequestTerseUpdate;
178 public event GetCameraData OnPhysicsRequestingCameraData;
131 179
132 /// <summary> 180 /// <summary>
133 /// Subscribers to this event must synchronously handle the dictionary of collisions received, since the event 181 /// Subscribers to this event must synchronously handle the dictionary of collisions received, since the event
@@ -138,15 +186,47 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
138 public event OutOfBounds OnOutOfBounds; 186 public event OutOfBounds OnOutOfBounds;
139#pragma warning restore 67 187#pragma warning restore 67
140 188
189 public CameraData TryGetCameraData()
190 {
191 GetCameraData handler = OnPhysicsRequestingCameraData;
192 if (handler != null)
193 {
194 return handler();
195 }
196
197 return new CameraData { Valid = false };
198 }
199
141 public static PhysicsActor Null 200 public static PhysicsActor Null
142 { 201 {
143 get { return new NullPhysicsActor(); } 202 get { return new NullPhysicsActor(); }
144 } 203 }
145 204
205 public virtual bool Building { get; set; }
206
207 public virtual void getContactData(ref ContactData cdata)
208 {
209 cdata.mu = 0;
210 cdata.bounce = 0;
211 }
212
146 public abstract bool Stopped { get; } 213 public abstract bool Stopped { get; }
147 214
148 public abstract Vector3 Size { get; set; } 215 public abstract Vector3 Size { get; set; }
149 216
217 public virtual void setAvatarSize(Vector3 size, float feetOffset)
218 {
219 Size = size;
220 }
221
222 public virtual bool Phantom { get; set; }
223
224 public virtual bool IsVolumeDtc
225 {
226 get { return false; }
227 set { return; }
228 }
229
150 public virtual byte PhysicsShapeType { get; set; } 230 public virtual byte PhysicsShapeType { get; set; }
151 231
152 public abstract PrimitiveBaseShape Shape { set; } 232 public abstract PrimitiveBaseShape Shape { set; }
@@ -169,20 +249,21 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
169 /// XXX: Bizarrely, this cannot be "Terrain" or "Water" right now unless it really is simulating terrain or 249 /// XXX: Bizarrely, this cannot be "Terrain" or "Water" right now unless it really is simulating terrain or
170 /// water. This is not a problem due to the formatting of names given by prims and avatars. 250 /// water. This is not a problem due to the formatting of names given by prims and avatars.
171 /// </remarks> 251 /// </remarks>
172 public string Name { get; protected set; } 252 public string Name { get; set; }
173 253
174 /// <summary> 254 /// <summary>
175 /// This is being used by ODE joint code. 255 /// This is being used by ODE joint code.
176 /// </summary> 256 /// </summary>
177 public string SOPName; 257 public string SOPName;
178 258
259 public virtual void CrossingStart() { }
179 public abstract void CrossingFailure(); 260 public abstract void CrossingFailure();
180 261
181 public abstract void link(PhysicsActor obj); 262 public abstract void link(PhysicsActor obj);
182 263
183 public abstract void delink(); 264 public abstract void delink();
184 265
185 public abstract void LockAngularMotion(Vector3 axis); 266 public abstract void LockAngularMotion(byte axislocks);
186 267
187 public virtual void RequestPhysicsterseUpdate() 268 public virtual void RequestPhysicsterseUpdate()
188 { 269 {
@@ -245,6 +326,56 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
245 public abstract void VehicleRotationParam(int param, Quaternion rotation); 326 public abstract void VehicleRotationParam(int param, Quaternion rotation);
246 public abstract void VehicleFlags(int param, bool remove); 327 public abstract void VehicleFlags(int param, bool remove);
247 328
329 // This is an overridable version of SetVehicle() that works for all physics engines.
330 // This is VERY inefficient. It behoves any physics engine to override this and
331 // implement a more efficient setting of all the vehicle parameters.
332 public virtual void SetVehicle(object pvdata)
333 {
334 VehicleData vdata = (VehicleData)pvdata;
335 // vehicleActor.ProcessSetVehicle((VehicleData)vdata);
336
337 this.VehicleType = (int)vdata.m_type;
338 this.VehicleFlags(-1, false); // clears all flags
339 this.VehicleFlags((int)vdata.m_flags, false);
340
341 // Linear properties
342 this.VehicleVectorParam((int)Vehicle.LINEAR_MOTOR_DIRECTION, vdata.m_linearMotorDirection);
343 this.VehicleVectorParam((int)Vehicle.LINEAR_FRICTION_TIMESCALE, vdata.m_linearFrictionTimescale);
344 this.VehicleFloatParam((int)Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE, vdata.m_linearMotorDecayTimescale);
345 this.VehicleFloatParam((int)Vehicle.LINEAR_MOTOR_TIMESCALE, vdata.m_linearMotorTimescale);
346 this.VehicleVectorParam((int)Vehicle.LINEAR_MOTOR_OFFSET, vdata.m_linearMotorOffset);
347
348 //Angular properties
349 this.VehicleVectorParam((int)Vehicle.ANGULAR_MOTOR_DIRECTION, vdata.m_angularMotorDirection);
350 this.VehicleFloatParam((int)Vehicle.ANGULAR_MOTOR_TIMESCALE, vdata.m_angularMotorTimescale);
351 this.VehicleFloatParam((int)Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE, vdata.m_angularMotorDecayTimescale);
352 this.VehicleVectorParam((int)Vehicle.ANGULAR_FRICTION_TIMESCALE, vdata.m_angularFrictionTimescale);
353
354 //Deflection properties
355 this.VehicleFloatParam((int)Vehicle.ANGULAR_DEFLECTION_EFFICIENCY, vdata.m_angularDeflectionEfficiency);
356 this.VehicleFloatParam((int)Vehicle.ANGULAR_DEFLECTION_TIMESCALE, vdata.m_angularDeflectionTimescale);
357 this.VehicleFloatParam((int)Vehicle.LINEAR_DEFLECTION_EFFICIENCY, vdata.m_linearDeflectionEfficiency);
358 this.VehicleFloatParam((int)Vehicle.LINEAR_DEFLECTION_TIMESCALE, vdata.m_linearDeflectionTimescale);
359
360 //Banking properties
361 this.VehicleFloatParam((int)Vehicle.BANKING_EFFICIENCY, vdata.m_bankingEfficiency);
362 this.VehicleFloatParam((int)Vehicle.BANKING_MIX, vdata.m_bankingMix);
363 this.VehicleFloatParam((int)Vehicle.BANKING_TIMESCALE, vdata.m_bankingTimescale);
364
365 //Hover and Buoyancy properties
366 this.VehicleFloatParam((int)Vehicle.HOVER_HEIGHT, vdata.m_VhoverHeight);
367 this.VehicleFloatParam((int)Vehicle.HOVER_EFFICIENCY, vdata.m_VhoverEfficiency);
368 this.VehicleFloatParam((int)Vehicle.HOVER_TIMESCALE, vdata.m_VhoverTimescale);
369 this.VehicleFloatParam((int)Vehicle.BUOYANCY, vdata.m_VehicleBuoyancy);
370
371 //Attractor properties
372 this.VehicleFloatParam((int)Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, vdata.m_verticalAttractionEfficiency);
373 this.VehicleFloatParam((int)Vehicle.VERTICAL_ATTRACTION_TIMESCALE, vdata.m_verticalAttractionTimescale);
374
375 this.VehicleRotationParam((int)Vehicle.REFERENCE_FRAME, vdata.m_referenceFrame);
376 }
377
378
248 /// <summary> 379 /// <summary>
249 /// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 380 /// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
250 /// </summary> 381 /// </summary>
@@ -253,6 +384,22 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
253 public abstract Vector3 GeometricCenter { get; } 384 public abstract Vector3 GeometricCenter { get; }
254 public abstract Vector3 CenterOfMass { get; } 385 public abstract Vector3 CenterOfMass { get; }
255 386
387 public virtual float PhysicsCost
388 {
389 get
390 {
391 return 0.1f;
392 }
393 }
394
395 public virtual float StreamCost
396 {
397 get
398 {
399 return 1.0f;
400 }
401 }
402
256 /// <summary> 403 /// <summary>
257 /// The desired velocity of this actor. 404 /// The desired velocity of this actor.
258 /// </summary> 405 /// </summary>
@@ -271,6 +418,7 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
271 } 418 }
272 419
273 public abstract Vector3 Velocity { get; set; } 420 public abstract Vector3 Velocity { get; set; }
421 public virtual Vector3 rootVelocity { get { return Vector3.Zero; } }
274 422
275 public abstract Vector3 Torque { get; set; } 423 public abstract Vector3 Torque { get; set; }
276 public abstract float CollisionScore { get; set;} 424 public abstract float CollisionScore { get; set;}
@@ -296,7 +444,7 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
296 444
297 // Used for llSetHoverHeight and maybe vehicle height 445 // Used for llSetHoverHeight and maybe vehicle height
298 // Hover Height will override MoveTo target's Z 446 // Hover Height will override MoveTo target's Z
299 public abstract bool PIDHoverActive { set;} 447 public abstract bool PIDHoverActive {get; set;}
300 public abstract float PIDHoverHeight { set;} 448 public abstract float PIDHoverHeight { set;}
301 public abstract PIDHoverType PIDHoverType { set;} 449 public abstract PIDHoverType PIDHoverType { set;}
302 public abstract float PIDHoverTau { set;} 450 public abstract float PIDHoverTau { set;}
@@ -306,7 +454,7 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
306 public abstract bool APIDActive { set;} 454 public abstract bool APIDActive { set;}
307 public abstract float APIDStrength { set;} 455 public abstract float APIDStrength { set;}
308 public abstract float APIDDamping { set;} 456 public abstract float APIDDamping { set;}
309 457
310 public abstract void AddForce(Vector3 force, bool pushforce); 458 public abstract void AddForce(Vector3 force, bool pushforce);
311 public abstract void AddAngularForce(Vector3 force, bool pushforce); 459 public abstract void AddAngularForce(Vector3 force, bool pushforce);
312 public abstract void SetMomentum(Vector3 momentum); 460 public abstract void SetMomentum(Vector3 momentum);
@@ -314,6 +462,29 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
314 public abstract void UnSubscribeEvents(); 462 public abstract void UnSubscribeEvents();
315 public abstract bool SubscribedEvents(); 463 public abstract bool SubscribedEvents();
316 464
465 public virtual void AddCollisionEvent(uint CollidedWith, ContactPoint contact) { }
466 public virtual void AddVDTCCollisionEvent(uint CollidedWith, ContactPoint contact) { }
467
468 public virtual PhysicsInertiaData GetInertiaData()
469 {
470 PhysicsInertiaData data = new PhysicsInertiaData();
471 data.TotalMass = this.Mass;
472 data.CenterOfMass = CenterOfMass - Position;
473 data.Inertia = Vector3.Zero;
474 data.InertiaRotation = Vector4.Zero;
475 return data;
476 }
477
478 public virtual void SetInertiaData(PhysicsInertiaData inertia)
479 {
480 }
481
482 public virtual float SimulationSuspended { get; set; }
483
484 // Warning in a parent part it returns itself, not null
485 public virtual PhysicsActor ParentActor { get { return this; } }
486
487
317 // Extendable interface for new, physics engine specific operations 488 // Extendable interface for new, physics engine specific operations
318 public virtual object Extension(string pFunct, params object[] pParams) 489 public virtual object Extension(string pFunct, params object[] pParams)
319 { 490 {
@@ -324,9 +495,11 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
324 495
325 public class NullPhysicsActor : PhysicsActor 496 public class NullPhysicsActor : PhysicsActor
326 { 497 {
498 private ActorTypes m_actorType = ActorTypes.Unknown;
499
327 public override bool Stopped 500 public override bool Stopped
328 { 501 {
329 get{ return false; } 502 get{ return true; }
330 } 503 }
331 504
332 public override Vector3 Position 505 public override Vector3 Position
@@ -343,6 +516,7 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
343 516
344 public override uint LocalID 517 public override uint LocalID
345 { 518 {
519 get { return 0; }
346 set { return; } 520 set { return; }
347 } 521 }
348 522
@@ -402,50 +576,17 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
402 set { return; } 576 set { return; }
403 } 577 }
404 578
405 public override void VehicleFloatParam(int param, float value) 579 public override void VehicleFloatParam(int param, float value) {}
406 { 580 public override void VehicleVectorParam(int param, Vector3 value) { }
581 public override void VehicleRotationParam(int param, Quaternion rotation) { }
582 public override void VehicleFlags(int param, bool remove) { }
583 public override void SetVolumeDetect(int param) {}
584 public override void SetMaterial(int material) {}
585 public override Vector3 CenterOfMass { get { return Vector3.Zero; }}
407 586
408 } 587 public override Vector3 GeometricCenter { get { return Vector3.Zero; }}
409
410 public override void VehicleVectorParam(int param, Vector3 value)
411 {
412 588
413 } 589 public override PrimitiveBaseShape Shape { set { return; }}
414
415 public override void VehicleRotationParam(int param, Quaternion rotation)
416 {
417
418 }
419
420 public override void VehicleFlags(int param, bool remove)
421 {
422
423 }
424
425 public override void SetVolumeDetect(int param)
426 {
427
428 }
429
430 public override void SetMaterial(int material)
431 {
432
433 }
434
435 public override Vector3 CenterOfMass
436 {
437 get { return Vector3.Zero; }
438 }
439
440 public override Vector3 GeometricCenter
441 {
442 get { return Vector3.Zero; }
443 }
444
445 public override PrimitiveBaseShape Shape
446 {
447 set { return; }
448 }
449 590
450 public override Vector3 Velocity 591 public override Vector3 Velocity
451 { 592 {
@@ -465,9 +606,7 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
465 set { } 606 set { }
466 } 607 }
467 608
468 public override void CrossingFailure() 609 public override void CrossingFailure() {}
469 {
470 }
471 610
472 public override Quaternion Orientation 611 public override Quaternion Orientation
473 { 612 {
@@ -507,8 +646,20 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
507 646
508 public override int PhysicsActorType 647 public override int PhysicsActorType
509 { 648 {
510 get { return (int) ActorTypes.Unknown; } 649 get { return (int)m_actorType; }
511 set { return; } 650 set {
651 ActorTypes type = (ActorTypes)value;
652 switch (type)
653 {
654 case ActorTypes.Ground:
655 case ActorTypes.Water:
656 m_actorType = type;
657 break;
658 default:
659 m_actorType = ActorTypes.Unknown;
660 break;
661 }
662 }
512 } 663 }
513 664
514 public override bool Kinematic 665 public override bool Kinematic
@@ -517,26 +668,11 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
517 set { return; } 668 set { return; }
518 } 669 }
519 670
520 public override void link(PhysicsActor obj) 671 public override void link(PhysicsActor obj) { }
521 { 672 public override void delink() { }
522 } 673 public override void LockAngularMotion(byte axislocks) { }
523 674 public override void AddForce(Vector3 force, bool pushforce) { }
524 public override void delink() 675 public override void AddAngularForce(Vector3 force, bool pushforce) { }
525 {
526 }
527
528 public override void LockAngularMotion(Vector3 axis)
529 {
530 }
531
532 public override void AddForce(Vector3 force, bool pushforce)
533 {
534 }
535
536 public override void AddAngularForce(Vector3 force, bool pushforce)
537 {
538
539 }
540 676
541 public override Vector3 RotationalVelocity 677 public override Vector3 RotationalVelocity
542 { 678 {
@@ -546,39 +682,28 @@ namespace OpenSim.Region.PhysicsModules.SharedBase
546 682
547 public override Vector3 PIDTarget { set { return; } } 683 public override Vector3 PIDTarget { set { return; } }
548 684
549 public override bool PIDActive 685 public override bool PIDActive
550 { 686 {
551 get { return false; } 687 get { return false; }
552 set { return; } 688 set { return; }
553 } 689 }
554 690
555 public override float PIDTau { set { return; } } 691 public override float PIDTau { set { return; } }
556 692
557 public override float PIDHoverHeight { set { return; } } 693 public override float PIDHoverHeight { set { return; } }
558 public override bool PIDHoverActive { set { return; } } 694 public override bool PIDHoverActive {get {return false;} set { return; } }
559 public override PIDHoverType PIDHoverType { set { return; } } 695 public override PIDHoverType PIDHoverType { set { return; } }
560 public override float PIDHoverTau { set { return; } } 696 public override float PIDHoverTau { set { return; } }
561 697
562 public override Quaternion APIDTarget { set { return; } } 698 public override Quaternion APIDTarget { set { return; } }
563 public override bool APIDActive { set { return; } } 699 public override bool APIDActive { set { return; } }
564 public override float APIDStrength { set { return; } } 700 public override float APIDStrength { set { return; } }
565 public override float APIDDamping { set { return; } } 701 public override float APIDDamping { set { return; } }
566
567 public override void SetMomentum(Vector3 momentum)
568 {
569 }
570
571 public override void SubscribeEvents(int ms)
572 {
573 702
574 } 703 public override void SetMomentum(Vector3 momentum) { }
575 public override void UnSubscribeEvents()
576 {
577 704
578 } 705 public override void SubscribeEvents(int ms) { }
579 public override bool SubscribedEvents() 706 public override void UnSubscribeEvents() { }
580 { 707 public override bool SubscribedEvents() { return false; }
581 return false;
582 }
583 } 708 }
584} 709}