Changeset 8105
- Timestamp:
- Mar 23, 2011, 12:13:34 PM (14 years ago)
- Location:
- code/branches/tetris
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/tetris/doc/api/Groups.dox
r7679 r8105 486 486 487 487 @image html pickupmodule.png 488 488 */ 489 490 /** 489 491 @defgroup PickupItems Items 490 492 @ingroup Pickup … … 496 498 @defgroup Pong Pong 497 499 @ingroup Modules 500 501 Pong is a minigame. 498 502 */ 499 503 -
code/branches/tetris/src/modules/pickup/Pickup.h
r7547 r8105 81 81 The Pickup class offers (useful) base functionality for a wide range of pickups. 82 82 83 Pickups in geriting from this class can choose an activation type and a duration type.83 Pickups inheriting from this class can choose an activation type and a duration type. 84 84 - The <b>activationType</b> deals with what happens to the Pickup as soon as it is picked up. It can either be set to <em>immediate</em>, which means that the Pickup is activated/used immediately upon being picked up. Or to <em>onUse</em>, which means, that the Pickup will be activated/used if some outside entity (most commonly the player through the PickupInventory) decides to use it. Default is <em>immediate</em>. 85 85 - The <b>durationType</b> deals with whether the Pickup has a continuous effect or whether its effect is focused on a singular instant. It can either be set to <em>once</em>, which means, that the Pickup just has an effect (at a singular instant in time) and is done once that effect has been applied. Or to <em>continuous</em>, which means that the effect of the Pickup unfolds over some timespan. Default is <em>once</em>. -
code/branches/tetris/src/modules/pong/Pong.h
r8104 r8105 48 48 @brief 49 49 Implements a Pong minigame. 50 51 //TODO: Add details to different classes used and how. 50 It connects the different entities present in a game of Pong. 51 52 //TODO: List and add details to different classes used and how. 52 53 PongBall, is the ball, PongBats are the things that can be moved by the players (ControllableEntities), PongCenterpoint is the playing field. (x-z area) 53 54 -
code/branches/tetris/src/modules/pong/PongBall.cc
r8104 r8105 101 101 @brief 102 102 Is called every tick. 103 //TODO: Explain in detail what happens here.103 Handles the movement of the ball and its interaction with the boundaries and bats. 104 104 @param dt 105 105 The time since the last tick. … … 226 226 /** 227 227 @brief 228 Set the 228 Set the bats for the ball. 229 @param bats 230 An array (of size 2) of weak pointers, to be set as the new bats. 229 231 */ 230 232 void PongBall::setBats(WeakPtr<PongBat>* bats) 231 233 { 232 if (this->bDeleteBats_) 234 if (this->bDeleteBats_) // If there are already some bats, delete them. 233 235 { 234 236 delete[] this->bat_; … … 237 239 238 240 this->bat_ = bats; 241 // Also store their object IDs, for synchronization. 239 242 this->batID_[0] = this->bat_[0]->getObjectID(); 240 243 this->batID_[1] = this->bat_[1]->getObjectID(); 241 244 } 242 245 246 /** 247 @brief 248 Get the bats over the network. 249 */ 243 250 void PongBall::applyBats() 244 251 { 245 if (!this->bat_) 252 // Make space for the bats, if they don't exist, yet. 253 if (this->bat_ == NULL) 246 254 { 247 255 this->bat_ = new WeakPtr<PongBat>[2]; -
code/branches/tetris/src/modules/pong/PongBall.h
r8104 r8105 47 47 /** 48 48 @brief 49 This class manages the ball for Pong.49 This class manages the ball for @ref orxonox::Pong "Pong". 50 50 51 //TODO: Describe what it's responnsibilities are. 52 Only moves in x-z area. 51 It is responsible for both the movement of the ball in the x,z-plane as well as its interaction with the boundaries of the playing field (defined by the @ref orxonox::PongCenterpoint "PongCenterpoint") and the @ref orxonox::PongBat "PongBats". Or more precisely, it makes the ball bounce off then upper and lower delimiters of the playing field, it makes the ball bounce off the bats and also detects when a player scores and takes appropriate measures. 53 52 54 53 @author … … 65 64 virtual void tick(float dt); 66 65 66 /** 67 @brief Set the dimensions of the playing field. 68 @param width The width of the playing field. 69 @param height The height of the playing field. 70 */ 67 71 void setFieldDimension(float width, float height) 68 72 { this->fieldWidth_ = width; this->fieldHeight_ = height; } 73 /** 74 @brief Get the dimensions of the playing field. 75 @param dimension A vector with the width as the first and height as the second component. 76 */ 69 77 void setFieldDimension(const Vector2& dimension) 70 78 { this->setFieldDimension(dimension.x, dimension.y); } 79 /** 80 @brief Get the dimensions of the playing field. 81 @return Returns a vector with the width as the first and height as the second component. 82 */ 71 83 Vector2 getFieldDimension() const 72 84 { return Vector2(this->fieldWidth_, this->fieldHeight_); } 73 85 74 void setSpeed(float speed); 86 void setSpeed(float speed); //!< Set the speed of the ball (in x-direction). 87 /** 88 @brief Get the speed of the ball (in x-direction). 89 @return Returns the speed of the ball (in x-direction). 90 */ 75 91 float getSpeed() const 76 92 { return this->speed_; } 77 93 94 /** 95 @brief Set the acceleration factor of the ball. 96 @param factor The factor the acceleration of the ball is set to. 97 */ 78 98 void setAccelerationFactor(float factor) 79 99 { this->accelerationFactor_ = factor; } 100 /** 101 @brief Get the acceleration factor of the ball. 102 @return Returns the acceleration factor of the ball. 103 */ 80 104 float getAccelerationFactor() const 81 105 { return this->accelerationFactor_; } 82 106 107 /** 108 @brief Set the length of the bats. 109 @param batlength The length of the bats (in z-direction) as percentage of the height of the playing field. 110 */ 83 111 void setBatLength(float batlength) 84 112 { this->batlength_ = batlength; } 113 /** 114 @brief Get the length of the bats. 115 @return Returns the length of the bats (in z-direction) as percentage of the height of the playing field. 116 */ 85 117 float getBatLength() const 86 118 { return this->batlength_; } 87 119 88 void setBats(WeakPtr<PongBat>* bats); 89 void applyBats(); 120 void setBats(WeakPtr<PongBat>* bats); //!< Set the bats for the ball. 121 void applyBats(); //!< Get the bats over the network. 90 122 123 // TODO: What is this exactly? 91 124 static const float MAX_REL_Z_VELOCITY; 92 125 … … 94 127 void registerVariables(); 95 128 96 float fieldWidth_; 97 float fieldHeight_; 98 float speed_; 99 float accelerationFactor_; 100 float batlength_; 101 WeakPtr<PongBat>* bat_; 102 bool bDeleteBats_; 103 unsigned int* batID_; 104 float relMercyOffset_; 129 float fieldWidth_; //!< The width of the playing field. 130 float fieldHeight_; //!< The height of the playing field. 131 float speed_; //!< The speed (in x-direction) of the ball. 132 float accelerationFactor_; //!< The acceleration factor of the ball. 133 float batlength_; //!< The length of the bats (in z-direction) as percentage of the height of the playing field. 134 WeakPtr<PongBat>* bat_; //!< An array with the two bats. 135 bool bDeleteBats_; //!< Bool, to keep track, of whether bat_ exists or not. 136 unsigned int* batID_; //!< The object IDs of the bats, to be able to synchronize them over the network. 137 float relMercyOffset_; //!< Offset, that makes the player not loose, when, in all fairness, he would have. 105 138 }; 106 139 } -
code/branches/tetris/src/modules/pong/PongBat.cc
r5781 r8105 27 27 */ 28 28 29 /** 30 @file PongBat.cc 31 @brief Implementation of the PongBat class. 32 */ 33 29 34 #include "PongBat.h" 30 35 … … 36 41 CreateFactory(PongBat); 37 42 43 /** 44 @brief 45 Constructor. Registers and initializes the object. 46 */ 38 47 PongBat::PongBat(BaseObject* creator) : ControllableEntity(creator) 39 48 { … … 50 59 } 51 60 61 /** 62 @brief 63 Registers variables to be synchronized over the network. 64 */ 52 65 void PongBat::registerVariables() 53 66 { … … 57 70 } 58 71 72 /** 73 @brief 74 Is called each tick. 75 //TODO detailed 76 @param dt 77 The time since last tick. 78 */ 59 79 void PongBat::tick(float dt) 60 80 { 81 // If the bat is controlled (but not over the network). 61 82 if (this->hasLocalController()) 62 83 { 63 84 if (this->movement_ != 0) 64 85 { 86 // The absolute value of the movement is restricted to be lesser or equal than the speed of the bat. 65 87 this->movement_ = clamp(this->movement_, -1.0f, 1.0f) * this->speed_; 66 88 89 //TODO What does this? 67 90 if (this->bMoveLocal_) 68 91 this->setVelocity(this->getOrientation() * Vector3(this->movement_, 0, 0)); … … 84 107 SUPER(PongBat, tick, dt); 85 108 109 // Restrict the position of the bats, for them to always be between the upper and lower delimiters. i.e. the bats stall if they reach the upper or lower boundary. 86 110 Vector3 position = this->getPosition(); 87 111 if (position.z > this->fieldHeight_ / 2 - this->fieldHeight_ * this->length_ / 2) … … 96 120 } 97 121 122 /** 123 @brief 124 Overloaded the function to steer the bat up and down. 125 @param value 126 A vector whose first component is the inverse direction in which we want to steer the bat. 127 */ 98 128 void PongBat::moveFrontBack(const Vector2& value) 99 129 { … … 102 132 } 103 133 134 /** 135 @brief 136 Overloaded the function to steer the bat up and down. 137 @param value 138 A vector whose first component is the direction in which we wnat to steer the bat. 139 */ 104 140 void PongBat::moveRightLeft(const Vector2& value) 105 141 { … … 108 144 } 109 145 146 /** 147 @brief 148 Is called when the player changed. 149 */ 110 150 void PongBat::changedPlayer() 111 151 { -
code/branches/tetris/src/modules/pong/PongBat.h
r7163 r8105 27 27 */ 28 28 29 /** 30 @file PongBat.h 31 @brief Declaration of the PongBat class. 32 @ingroup Pong 33 */ 34 29 35 #ifndef _PongBat_H__ 30 36 #define _PongBat_H__ 31 37 32 38 #include "pong/PongPrereqs.h" 39 33 40 #include "worldentities/ControllableEntity.h" 34 41 35 42 namespace orxonox 36 43 { 44 45 /** 46 @brief 47 The PongBat class manages the bats for @ref orxonox::Pong "Pong", which are the elements controlled by the player. 48 49 It is responsible for the movement (controlled by the players) of the bat. 50 51 @author 52 Fabian 'x3n' Landau 53 54 @ingroup Pong 55 */ 37 56 class _PongExport PongBat : public ControllableEntity 38 57 { 39 58 public: 40 PongBat(BaseObject* creator); 59 PongBat(BaseObject* creator); //!< Constructor. Registers and initializes the object. 41 60 virtual ~PongBat() {} 42 61 43 62 virtual void tick(float dt); 44 63 45 virtual void moveFrontBack(const Vector2& value); 46 virtual void moveRightLeft(const Vector2& value); 64 virtual void moveFrontBack(const Vector2& value); //!< Overloaded the function to steer the bat up and down. 65 virtual void moveRightLeft(const Vector2& value); //!< Overloaded the function to steer the bat up and down. 47 66 48 virtual void changedPlayer(); 67 virtual void changedPlayer(); //!< Is called when the player changed. 49 68 69 /** 70 @brief Set the speed of the bat. 71 @param speed The speed to be set. 72 */ 50 73 void setSpeed(float speed) 51 74 { this->speed_ = speed; } 75 /** 76 @brief Get the speed of the bat. 77 @return Returns the speed of the bat. 78 */ 52 79 float getSpeed() const 53 80 { return this->speed_; } 54 81 82 /** 83 @brief Set the height of the playing field. 84 @param height The height of the playing field. 85 */ 55 86 void setFieldHeight(float height) 56 87 { this->fieldHeight_ = height; } 88 /** 89 @brief Get the height of the playing field. 90 @return Returns the height of the playing field. 91 */ 57 92 float getFieldHeight() const 58 93 { return this->fieldHeight_; } 59 94 95 /** 96 @brief Set the length of the bat. 97 @param length The length of the bat (in z-direction) as percentage of the height of the playing field. 98 */ 60 99 void setLength(float length) 61 100 { this->length_ = length; } 101 /** 102 @brief get the length of the bat. 103 @return Returns the length of the bat (in z-direction) as percentage of the height of the playing field. 104 */ 62 105 float getLength() const 63 106 { return this->length_; } 64 107 65 108 private: 66 void registerVariables(); 109 void registerVariables(); //!< Registers variables to be synchronized over the network. 67 110 68 float movement_; 69 bool bMoveLocal_; 70 float speed_; 71 float length_; 72 float fieldHeight_; 73 bool bSteadiedPosition_; 111 float movement_; //!< The amount (and direction), in z-direction, of movement of the bat. 112 bool bMoveLocal_; //TODO ??? 113 float speed_; //!< The movementspeed of the bat. 114 float length_; //!< The length of the bat (in z-direction) as percentage of the height of the playing field. 115 float fieldHeight_; //!< The height of the playing field. 116 bool bSteadiedPosition_; //TODO: ??? 74 117 }; 75 118 } -
code/branches/tetris/src/modules/pong/PongCenterpoint.cc
r5929 r8105 27 27 */ 28 28 29 /** 30 @file PongCenterpoint.cc 31 @brief Implementation of the PongCenterpoint class. 32 */ 33 29 34 #include "PongCenterpoint.h" 30 35 31 36 #include "core/CoreIncludes.h" 32 37 #include "core/XMLPort.h" 38 33 39 #include "Pong.h" 34 40 … … 37 43 CreateFactory(PongCenterpoint); 38 44 45 /** 46 @brief 47 Constructor. Registers and initializes the object and checks whether the gametype is actually Pong. 48 */ 39 49 PongCenterpoint::PongCenterpoint(BaseObject* creator) : StaticEntity(creator) 40 50 { … … 51 61 } 52 62 63 /** 64 @brief 65 Method to create a PongCenterpoint through XML. 66 */ 53 67 void PongCenterpoint::XMLPort(Element& xmlelement, XMLPort::Mode mode) 54 68 { … … 64 78 } 65 79 80 /** 81 @brief 82 Is called when the gametype has changed. 83 */ 66 84 void PongCenterpoint::changedGametype() 67 85 { 68 86 SUPER(PongCenterpoint, changedGametype); 69 87 88 // Check, whether it's still Pong. 70 89 this->checkGametype(); 71 90 } 72 91 92 /** 93 @brief 94 Checks whether the gametype is Pong and if it is, sets its centerpoint. 95 */ 73 96 void PongCenterpoint::checkGametype() 74 97 { 75 if (this->getGametype() && this->getGametype()->isA(Class(Pong)))98 if (this->getGametype() != NULL && this->getGametype()->isA(Class(Pong))) 76 99 { 77 Pong* pong _gametype = orxonox_cast<Pong*>(this->getGametype().get());78 pong _gametype->setCenterpoint(this);100 Pong* pongGametype = orxonox_cast<Pong*>(this->getGametype().get()); 101 pongGametype->setCenterpoint(this); 79 102 } 80 103 } -
code/branches/tetris/src/modules/pong/PongCenterpoint.h
r5929 r8105 27 27 */ 28 28 29 /** 30 @file PongCenterpoint.h 31 @brief Declaration of the PongCenterpoint class. 32 @ingroup Pong 33 */ 34 29 35 #ifndef _PongCenterpoint_H__ 30 36 #define _PongCenterpoint_H__ … … 33 39 34 40 #include <string> 41 35 42 #include <util/Math.h> 43 36 44 #include "worldentities/StaticEntity.h" 37 45 38 46 namespace orxonox 39 47 { 48 49 /** 50 @brief 51 The PongCenterpoint implements the playing field @ref orxonox::Pong "Pong" takes place in and allows for many parameters of the minigame to be set. 52 The playing field resides in the x,z-plane, with the x-axis being the horizontal axis and the z-axis being the vertical axis. 53 54 Various parameters can be set: 55 - The <b>dimension</b> is a vector, that defines the width and height of the playing field. The default is <em>(200, 120)</em>. 56 - The <b>balltemplate</b> is a template that is applied to the @ref orxonox::PongBall "PongBall", it can be used to attach different things to it, e.g. its @ref orxonox::Model "Model". See below for a usage example. 57 - The <b>battemplate</b> is a template that is applied to the @ref orxonox::PongBall "PongBat", it can be used to attach different things to it, e.g. its @ref orxonox::Model "Model". See below for a usage example. 58 - The <b>ballspeed</b> is the speed with wich the @ref orxonox::PongBall "PongBall" moves. The default is <em>100</em>. 59 - The <b>ballaccfactor</b> is the acceleration factor for the @ref orxonox::PongBall "PongBall". The default is <em>1.0</em>. 60 - The <b>batspeed</b> is the speed with which the @ref orxonox::PongBat "PongBats" move. The default is <em>60</em>. 61 - The <b>batlength</b> is the length of the @ref orxonox::PongBat "PongBats" as the percentage of the height of the playing field. The default is <em>0.25</em>. 62 63 An example in XML of the PongCenterpoint would be: 64 65 First the needed templates: 66 The template for the @ref orxonox::PongBall "PongBall". 67 @code 68 <Template name="pongball"> 69 <PongBall> 70 <attached> 71 <Model mesh="sphere.mesh" scale="2" /> 72 <ParticleSpawner name="hiteffect" position="0,0,0" source="Orxonox/sparks2" lifetime="0.01" autostart="0" mainstate="spawn" /> 73 </attached> 74 <eventlisteners> 75 <EventTarget target="hiteffect" /> 76 </eventlisteners> 77 </PongBall> 78 </Template> 79 @endcode 80 As can be seen, a sphere is attached as the @ref orxonox::Model "Model" for the @ref orxonox::PongBall "PongBall", and also an @ref orxonox::EventListener "EventListener" that triggers a @ref orxonox::ParticleSpawner "ParticleSpawner", whenever the ball hits the boundaries is attached. 81 82 Additionally the template for the @ref orxonox::PongBat "PongBat". 83 @code 84 <Template name="pongbatcameras" defaults="0"> 85 <PongBat> 86 <camerapositions> 87 <CameraPosition position="0,200,0" pitch="-90" absolute="true" /> 88 </camerapositions> 89 </PongBat> 90 </Template> 91 92 <Template name="pongbat"> 93 <PongBat camerapositiontemplate=pongbatcameras> 94 <attached> 95 <Model position="0,0,3" mesh="cube.mesh" scale3D="14,2,2" /> 96 </attached> 97 </PongBat> 98 </Template> 99 @endcode 100 As can be seen, there are actually two templates. The first template is needed to set the camera for the @ref orxonox::PongBat "PongBat". The second template ist the actual template for the @ref orxonox::PongBat "PongBat", the template for the camera position is added and a @ref orxonox::Model "Model" for the @ref orxonox::PongBat "PongBat" is attached. 101 102 Finally the PongCenterpoint is created. 103 @code 104 <PongCenterpoint name="pongcenter" dimension="200,120" balltemplate="pongball" battemplate="pongbat" ballspeed="200" ballaccfactor="1.0" batspeed="130" batlength="0.25"> 105 <attached> 106 <Model position="0,0,60" mesh="cube.mesh" scale3D="105,1,1" /> 107 <Model position="0,0,-60" mesh="cube.mesh" scale3D="105,1,1" /> 108 </attached> 109 </PongCenterpoint> 110 @endcode 111 All parameters are specified. And also two @ref orxonox::Model "Models" (for the upper and lower boundary) are attached. 112 113 For a more elaborate example, have a look at the <code>pong.oxw</code> level file. 114 115 @author 116 Fabian 'x3n' Landau 117 118 @ingroup Pong 119 */ 40 120 class _PongExport PongCenterpoint : public StaticEntity 41 121 { 42 122 public: 43 PongCenterpoint(BaseObject* creator); 123 PongCenterpoint(BaseObject* creator); //!< Constructor. Registers and initializes the object and checks whether the gametype is actually Pong. 44 124 virtual ~PongCenterpoint() {} 45 125 46 virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode); 47 48 virtual void changedGametype(); 49 126 virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode); //!< Method to create a PongCenterpoint through XML. 127 128 virtual void changedGametype(); //!< Is called when the gametype has changed. 129 130 /** 131 @brief Set the template for the ball. (e.g. to attach the model of the ball, but also to attach an EventListener to it to detect, when it hits the boundaries, and e.g. display some ParticleEffets, when it does.) 132 @param balltemplate The name of the template to be set. 133 */ 50 134 void setBalltemplate(const std::string& balltemplate) 51 135 { this->balltemplate_ = balltemplate; } 136 /** 137 @brief Get the template of the ball. 138 @return Returns the name of the template of the ball. 139 */ 52 140 const std::string& getBalltemplate() const 53 141 { return this->balltemplate_; } 54 142 143 /** 144 @brief Set the template for the bats. (e.g. to attach the model of the bat, but also to attach CameraPositions to it, to be able to view the game from the bats perspective) 145 @param battemplate The name of the template to be set. 146 */ 55 147 void setBattemplate(const std::string& battemplate) 56 148 { this->battemplate_ = battemplate; } 149 /** 150 @brief Get the template of the bats. 151 @return Returns the name of the template of the bats. 152 */ 57 153 const std::string& getBattemplate() const 58 154 { return this->battemplate_; } 59 155 156 /** 157 @brief Set the dimensions of the playing field. 158 @param dimension A vector with the width of the playing field as first component and the height as second. 159 */ 60 160 void setFieldDimension(const Vector2& dimension) 61 161 { this->width_ = dimension.x; this->height_ = dimension.y; } 162 /** 163 @brief Get the dimensions of the playing field. 164 @return Returns a vector with the width of the playing field as first component and the height as second. 165 */ 62 166 Vector2 getFieldDimension() const 63 167 { return Vector2(this->width_, this->height_); } 64 168 169 /** 170 @brief Set the speed of the ball. 171 @param ballspeed The speed of the ball. 172 */ 65 173 void setBallSpeed(float ballspeed) 66 174 { this->ballspeed_ = ballspeed; } 175 /** 176 @brief Get the speed of the ball. 177 @return Returns the speed of the ball. 178 */ 67 179 float getBallSpeed() const 68 180 { return this->ballspeed_; } 69 181 182 /** 183 @brief Set the ball's acceleration factor. 184 @param ballaccfactor The ball's acceleration factor. 185 */ 70 186 void setBallAccelerationFactor(float ballaccfactor) 71 187 { this->ballaccfactor_ = ballaccfactor; } 188 /** 189 @brief Get the ball's acceleration factor 190 @return Returns the ball's acceleration factor. 191 */ 72 192 float getBallAccelerationFactor() const 73 193 { return this->ballaccfactor_; } 74 194 195 /** 196 @brief Set the speed of the bats. 197 @param batspeed The speed of the bats. 198 */ 75 199 void setBatSpeed(float batspeed) 76 200 { this->batspeed_ = batspeed; } 201 /** 202 @brief Get the speed of the bats. 203 @return Returns the speed of the bats. 204 */ 77 205 float getBatSpeed() const 78 206 { return this->batspeed_; } 79 207 208 /** 209 @brief Set the length of the bats. 210 @param batlength The length of the bats (in z-direction) as a percentage of the height of the playing field. 211 */ 80 212 void setBatLength(float batlength) 81 213 { this->batlength_ = batlength; } 214 /** 215 @brief Get the length of the bats. 216 @return Returns the length of the bats (in z-direction) as a percentage of the height of the playing field. 217 */ 82 218 float getBatLength() const 83 219 { return this->batlength_; } 84 220 85 221 private: 86 void checkGametype(); 87 88 std::string balltemplate_; 89 std::string battemplate_; 90 91 float ballspeed_; 92 float ballaccfactor_; 93 float batspeed_; 94 float batlength_; 95 96 float width_; 97 float height_; 222 void checkGametype(); //!< Checks whether the gametype is Pong and if it is, sets its centerpoint. 223 224 std::string balltemplate_; //!< The template for the ball. 225 std::string battemplate_; //!< The template for the batts. 226 227 float ballspeed_; //!< The speed of then ball. 228 float ballaccfactor_; //!< The acceleration factor of the ball. 229 float batspeed_; //!< The speed of the bat. 230 float batlength_; //!< The length of the bat (in z-direction) as a percentage of the height of the playing field. 231 232 float width_; //!< The height of the playing field. 233 float height_; //!< The width of the playing field. 98 234 }; 99 235 }
Note: See TracChangeset
for help on using the changeset viewer.