Changeset 11644
- Timestamp:
- Dec 8, 2017, 2:55:15 PM (7 years ago)
- Location:
- code/branches/Dialog_HS17
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/Dialog_HS17/data/gui/layouts/Dialog.layout
r11642 r11644 31 31 </Window> 32 32 33 <Window Type="MenuWidgets/StaticText" Name="orxonox/DialogAns" > 34 <Property Name="InheritsAlpha" Value="False" /> 35 <Property Name="HorzFormatting" Value="HorzCentred" /> 33 <Window Type="MenuWidgets/Listbox" Name="orxonox/AnsListbox" > 36 34 <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> 37 <Property Name="VertFormatting" Value="TopAligned" /> 38 <Property Name="UnifiedAreaRect" Value="{{0.604166,0},{0.15,0},{0.958333,0},{0.636,0}}" /> 39 <Window Type="MenuWidgets/Listbox" Name="orxonox/AnsListbox" > 40 <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> 41 <Property Name="UnifiedAreaRect" Value="{{0.05,0},{0.225,0},{0.95,0},{0.92,0}}" /> 42 <Event Name="ItemSelectionChanged" Function="Dialog.answer_changed" /> 43 </Window> 35 <Property Name="UnifiedAreaRect" Value="{{0.05,0},{0.225,0},{0.95,0},{0.85,0}}" /> 36 <Event Name="ItemSelectionChanged" Function="Dialog.answer_changed" /> 44 37 </Window> 38 45 39 <Window Type="MenuWidgets/Button" Name="orxonox/SayButton" > 46 40 <Property Name="Text" Value="Say" /> -
code/branches/Dialog_HS17/data/gui/scripts/Dialog.lua
r11642 r11644 6 6 P.detailsWindows = {} 7 7 P.showing = false 8 P.choice = 0 8 9 9 -- Design parameters 10 P.imageHeight = 50 11 P.detailImageSize = 100 12 P.textHeight = 50 13 P.buttonWidth = 50 14 15 function P.onLoad() 10 function P.onLoad() --wird ausgefuert wenn Fenster geladen 16 11 P.wrapper = nil 17 12 end 18 13 19 function P.onShow() 14 function P.onShow() --wird ausgefuert wenn Dialogfenster gezeigt 20 15 21 16 orxonox.CommandExecutor:execute("setTimeFactor 0") … … 25 20 end 26 21 27 function P.onHide() 22 function P.onHide() --aufgefuert wenn Fenster geschlossen wird 28 23 orxonox.CommandExecutor:execute("setTimeFactor 1") 29 24 P.showing = false … … 31 26 end 32 27 33 function P.createDialog() 28 function P.createDialog() -- initiallisiert das Dialog Fenster, setzt Namen sowie die erste Frage mit enstprechenden Antworten 34 29 35 30 local manager = orxonox.DialogManager:getInstance() … … 44 39 questionfiled:setText(question) 45 40 46 listboxwindow = winMgr:getWindow("orxonox/AnsListbox") 41 local listboxwindow = winMgr:getWindow("orxonox/AnsListbox") 42 CEGUI.toListbox(listboxwindow):resetList() 47 43 48 local themeList = {} 49 --[[ 50 table.insert(themeList, "Default") 51 table.insert(themeList, "Drum n' Bass") 52 table.insert(themeList, "8-Bit Style") 53 table.insert(themeList, "Corny Jazz") 54 table.insert(themeList, "Metal") 55 --]] 44 local ansList = {} 56 45 local anssize = manager:getSize() 57 46 58 47 for index = 0, anssize -1, 1 do 59 table.insert( themeList, manager:getAnswer(index))48 table.insert(ansList, manager:getAnswer(index)) 60 49 end 61 50 62 for k,v in pairs( themeList) do51 for k,v in pairs(ansList) do 63 52 item = CEGUI.createListboxTextItem(v) 64 53 item:setSelectionBrushImage(menuImageSet, "MultiListSelectionBrush") … … 67 56 end 68 57 69 function P.updateDialog() 58 function P.updateDialog() --updated den Dialog entsprechend der Ausgeaehlten option der letzten Frage, setzt Frage und Antwortmoeglichkeiten neu 70 59 local manager = orxonox.DialogManager:getInstance() 71 --manager:update()60 manager:update(P.choice) 72 61 73 62 local questionfiled = winMgr:getWindow("orxonox/Dialog/Question") 74 63 local question = manager:getQuestion() 75 64 questionfiled:setText(question) 65 66 local listboxwindow = winMgr:getWindow("orxonox/AnsListbox") 67 listboxwindow:resetList() 68 69 local ansList = {} 70 local anssize = manager:getSize() 71 72 for index = 0, anssize -1, 1 do 73 table.insert(ansList, manager:getAnswer(index)) 74 end 75 76 for k,v in pairs(ansList) do 77 item = CEGUI.createListboxTextItem(v) 78 item:setSelectionBrushImage(menuImageSet, "MultiListSelectionBrush") 79 CEGUI.toListbox(listboxwindow):addItem(item) 80 end 81 82 P.choice = 0 76 83 end 77 84 78 function P.answer_changed(e) 79 -- body 85 function P.answer_changed(e) --wird aufgerufen falls Auswahl geaendert wird und setzt enstprechenden Indexparameter 86 listboxwindow = winMgr:getWindow("orxonox/AnsListbox") 87 selection = listboxwindow:getFirstSelectedItem() 88 if selection ~= nil then 89 P.choice = listboxwindow:getItemIndex(selection) 90 else 91 P.choice = 0 92 end 80 93 end 81 94 82 95 83 function P.cleanup(destroyDetails) 84 96 function P.cleanup(destroyDetails) --loest Fenster wieder auf (!nicht selbst geschrieben, nur uebernommen, eventuell nicht noetiger code) 97 85 98 if P.wrapper ~= nil then 86 99 winMgr:destroyWindow(P.wrapper) … … 101 114 102 115 103 function P.Button_clicked(e) 104 local ending = orxonox.DialogManager:getInstance():endtest() 105 orxonox.CommandExecutor:execute("OrxonoxOverlay toggleVisibility Dialog") 116 function P.Button_clicked(e) --wird bei click auf say knopf ausgeloest, entscheidet ob Dialog schliesst oder updated und fuert entsprechen aus 117 local ending = orxonox.DialogManager:getInstance():endtest(P.choice) 106 118 107 119 if ending then 108 120 orxonox.CommandExecutor:execute("OrxonoxOverlay toggleVisibility Dialog") 109 110 111 121 else 112 122 P.updateDialog(index) -
code/branches/Dialog_HS17/data/levels/DialogueShowcase2.oxw
r11642 r11644 1 1 <LevelInfo 2 name = "Dialog ueShowcase2"2 name = "DialogShowase" 3 3 description = "A level to show and test the functionality of the Dialogue module." 4 4 tags = "test" … … 32 32 <Backlight position="100,0,100" visible=true frequency=0.6 amplitude=3 material="Flares/lensflare" colour="1,0,1"/> 33 33 34 <Dialog name="Kurt" currentQuestionId="loop ">34 <Dialog name="Kurt" currentQuestionId="loop1"> 35 35 <questions> 36 <Question question="Soll ich dich loopen?" Id="loop">36 <Question question="Soll ich dich einmal loopen?" Id="loop1"> 37 37 <answerIds> 38 38 <AnswerId Id="ja"/> 39 39 <AnswerId Id="nein"/> 40 <AnswerId Id="giveItToMe"/> 41 </answerIds> 42 </Question> 43 <Question question="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua." Id="lorem"> 44 <answerIds> 45 <AnswerId Id="end"/> 46 </answerIds> 47 </Question> 48 <Question question="Soll ich dich nochmal loopen?" Id="loop2"> 49 <answerIds> 50 <AnswerId Id="ja"/> 51 <AnswerId Id="nein"/> 52 <AnswerId Id="end"/> 40 53 </answerIds> 41 54 </Question> … … 43 56 </questions> 44 57 <answers> 45 <Answer Id="ja" answer="ja loop mich" nextQuestionId="loop"/> 58 <Answer Id="giveItToMe" answer="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." nextQuestionId="lorem"/> 59 <Answer Id="ja" answer="ja loop mich" nextQuestionId="loop2"/> 46 60 <Answer Id="nein" answer="lieber nicht" nextQuestionId="ok"/> 61 <Answer Id="end" answer="ich geh dann mal" nextQuestionId=""/> 47 62 </answers> 48 63 <events> … … 52 67 </events> 53 68 </Dialog> 54 55 <DistanceTrigger name="test1" position="100,0,-100" target="Pawn" distance=25 stayActive="true" />56 <Backlight position="100,0,-100" visible=true frequency=0.6 amplitude=3 material="Flares/lensflare" colour="1,1,1"/>57 69 58 <NextQuestion question="Hey, sorry to bother you, could you help me with something?" a1="Yeah sure." a2="Nope get lost." >59 <possibleQuestions>60 <NextQuestion question="Do you like fish" a1="...yes?" a2="This is wasting my time." >61 <possibleQuestions>62 <NextQuestion question="Splendid! Would you like your ship to look like one?" a1="..." a2="I'm going now, okay?" />63 <NextQuestion question="Turtles then?" a1="..." a2="Im going now, okay?" />64 </possibleQuestions>65 </NextQuestion>66 <NextQuestion question="I can pay you know." a1="Got enough money." a2="...are you deaf? Bye."/>67 </possibleQuestions>68 <events>69 <execute>70 <EventListener event="test1" />71 </execute>72 </events>73 </NextQuestion>74 75 76 77 70 <Light type=directional position="0,0,0" direction="0.253, 0.593, -0.765" diffuse="1.0, 0.9, 0.9, 1.0" specular="1.0, 0.9, 0.9, 1.0"/> 78 71 <SpawnPoint team=0 position="-200,0,0" lookat="0,0,0" spawnclass=SpaceShip pawndesign=spaceshipescort /> -
code/branches/Dialog_HS17/src/modules/dialog/Answer.cc
r11611 r11644 23 23 } 24 24 25 void Answer::setAnswerId( std::stringanswerId){25 void Answer::setAnswerId(const std::string& answerId){ 26 26 this->answerId_ = answerId; 27 27 } 28 28 29 std::string Answer::getAnswerId(){ 29 const std::string& Answer::getAnswerId() const 30 { 30 31 return this->answerId_; 31 32 } 32 33 33 void Answer::setNextQuestion( std::stringnextId)34 void Answer::setNextQuestion(const std::string& nextId) 34 35 { 35 36 this->nextQuestionId_ = nextId; 36 37 } 37 38 38 std::string Answer::getNextQuestion()39 const std::string& Answer::getNextQuestion() const 39 40 { 40 41 return this->nextQuestionId_; 41 42 } 42 43 43 void Answer::setAnswer( std::stringanswer)44 void Answer::setAnswer(const std::string& answer) 44 45 { 45 46 this->answer_ = answer; 46 47 } 47 48 48 std::string Answer::getAnswer()49 const std::string& Answer::getAnswer() const 49 50 { 50 51 return this->answer_; -
code/branches/Dialog_HS17/src/modules/dialog/Answer.h
r11611 r11644 18 18 virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode); 19 19 20 void setAnswerId( std::string answerId);21 std::string getAnswerId();20 void setAnswerId(const std::string& answerId); //xmlPort-Funktion, setzt AntwortId 21 const std::string& getAnswerId() const; //xmlPort-Funktion, gibt AntwortId 22 22 23 void setNextQuestion( std::string nextId); // "end" um den dialog zu beenden24 std::string getNextQuestion();23 void setNextQuestion(const std::string& nextId); //xmlPort-Funktion, um Dialog zu beenden tag benutzen der von keiner Frage benutzt wird 24 const std::string& getNextQuestion() const; //xmlPort-Funktion, gibt Id der Folgefrage 25 25 26 void setAnswer( std::string awns);27 std::string getAnswer();26 void setAnswer(const std::string& awns); //xmlPort-Funktion, setzt Antworttext 27 const std::string& getAnswer() const; //xmlPort-Funktion, gibt Antworttext 28 28 29 29 private: -
code/branches/Dialog_HS17/src/modules/dialog/AnswerId.cc
r11611 r11644 19 19 } 20 20 21 void AnswerId::setId( std::stringid)21 void AnswerId::setId(const std::string& id) 22 22 { 23 23 this->id_ = id; 24 24 } 25 25 26 std::string AnswerId::getId()26 const std::string& AnswerId::getId() const 27 27 { 28 28 return this->id_; -
code/branches/Dialog_HS17/src/modules/dialog/AnswerId.h
r11611 r11644 16 16 virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode); 17 17 18 void setId( std::string Id);19 std::string getId();18 void setId(const std::string& Id); //allows to set Id, only use in xmlPort for initializing AnswerIds in lvl files 19 const std::string& getId() const; //allows to get Id, used in xmlPort 20 20 21 21 private: -
code/branches/Dialog_HS17/src/modules/dialog/Dialog.cc
r11642 r11644 35 35 } 36 36 37 void Dialog::setName( std::stringname)37 void Dialog::setName(const std::string& name) 38 38 { 39 39 this->name_ = name; 40 40 } 41 41 42 std::string Dialog::getName()42 const std::string& Dialog::getName() const 43 43 { 44 44 return this->name_; 45 45 } 46 46 47 void Dialog::setCurrentQuestionId( std::stringquestionId)47 void Dialog::setCurrentQuestionId(const std::string& questionId) 48 48 { 49 49 this->currentQuestionId_ = questionId; 50 50 } 51 51 52 std::string Dialog::getCurrentQuestionId()52 const std::string& Dialog::getCurrentQuestionId() const 53 53 { 54 54 return this->currentQuestionId_; … … 61 61 } 62 62 63 const Question* Dialog::getQuestion() const // returned nichts 64 { 65 return nullptr; 66 } 67 63 68 void Dialog::addAnswer(Answer* answer) //fuegt Answer der Map hinzu 64 69 { … … 66 71 } 67 72 68 Question* Dialog::getQuestion(unsigned int index) const // returned nichts73 const Answer* Dialog::getAnswer(unsigned int index) const //returned sting der Antwort zur Id. 69 74 { 70 75 return nullptr; 71 // Question question = (questions_.find(this->currentQuestionId_))->second;72 // return question.getQuestion();73 76 } 74 77 75 Answer* Dialog::getAnswer(unsigned int index) const //returned sting der Antwort zur Id.76 {77 return nullptr;78 // return (this->answers_.find(answerId))->second.getAnswer();79 }80 78 81 std::vector<std::string>* Dialog::getAnswerIds() // returned vector mit allen momentanen AntwortenIds79 const std::vector<std::string>* Dialog::getAnswerIds() // returned vector mit allen momentanen AntwortenIds 82 80 { 83 81 84 82 Question* question = (this->questions_.find(this->currentQuestionId_))->second; 85 std::vector<std::string>* answers = question->getAnswerIds();83 const std::vector<std::string>* answers = question->getAnswerIds(); 86 84 return answers; 87 85 … … 103 101 } 104 102 105 void Dialog::update( std::string givenAnswer)103 void Dialog::update(const std::string& givenAnswerId) 106 104 { 107 Answer* answer = (answers_.find(givenAnswer ))->second;105 Answer* answer = (answers_.find(givenAnswerId))->second; 108 106 this->currentQuestionId_ = answer->getNextQuestion(); 109 107 } 110 108 111 bool Dialog::ending( ) //retruned true wenn die Id der Antwort end ist oder keine Antworten auf die frage eingetragen sind109 bool Dialog::ending(const std::string& givenAnswerId) 112 110 { 113 bool end = false; 114 if ((this->questions_.find(this->currentQuestionId_)->second)->getAnswerIds()->empty()){ 115 end = true; 116 } 117 return end; 111 return !this->questions_.count(this->answers_.find(givenAnswerId)->second->getNextQuestion()); 118 112 } 119 113 120 std::stringDialog::getQuestionString()114 const std::string& Dialog::getQuestionString() 121 115 { 122 116 return this->questions_.find(this->currentQuestionId_)->second->getQuestion(); 123 117 } 124 118 125 std::stringDialog::getAnswerString(std::string answerId)119 const std::string& Dialog::getAnswerString(std::string answerId) 126 120 { 127 121 return this->answers_.find(answerId)->second->getAnswer(); -
code/branches/Dialog_HS17/src/modules/dialog/Dialog.h
r11642 r11644 24 24 virtual void XMLEventPort(Element& xmlelement, XMLPort::Mode mode); 25 25 26 void setName( std::string name);27 std::string getName();26 void setName(const std::string& name); //xmlPort-Funktion, setzt Namen 27 const std::string& getName() const; //xmlPort-Funktion, returnt Namen 28 28 29 void setCurrentQuestionId( std::string questionId);30 std::string getCurrentQuestionId();29 void setCurrentQuestionId(const std::string& questionId); //xmlPort-Funktion, setzt string Id der momentanen Frage 30 const std::string& getCurrentQuestionId() const; //xmlPort-Funktion, gibt Id der momentanen Frage 31 31 32 void addQuestion(Question* question); // fuegt Question der Map hinzu33 void addAnswer(Answer* answer); //fuegt Answer der Map hinzu32 void addQuestion(Question* question); //xmlPort-Funktion, fuegt Question der Map hinzu 33 const Question* getQuestion() const; //xmlPort-Funktion, returnt nullptr 34 34 35 Question* getQuestion(unsigned int index) const; // // benoetigt fuer xmlPort 36 Answer* getAnswer(unsigned int index) const; // benoetigt fuer xmlPort 37 std::vector<std::string>* getAnswerIds(); // returned vector mit allen momentanen AntwortenIds 35 void addAnswer(Answer* answer); //xmlPort-Funktion, fuegt Answer der Map hinzu 36 const Answer* getAnswer(unsigned int index) const; //xmlPort-Funktion, returnt nullptr 38 37 39 bool execute(bool bTriggered, BaseObject* trigger);40 38 41 void update(std::string givenAnswer);39 const std::vector<std::string>* getAnswerIds(); // returned Pointer auf Vector mit allen momentanen AntwortenIds 42 40 43 bool ending(); //retruned true wenn die Id der Antwort end ist oder keine Antworten auf die frage eingetragen sind41 bool execute(bool bTriggered, BaseObject* trigger); // funktion die aufgerufen wird wenn der im xml verbundene Trigger aktiviert wird 44 42 45 std::string getQuestionString(); //gibt string der momentanen Frage 46 std::string getAnswerString(std::string answerId); //gibt string der zur Id passenden Frage 43 void update(const std::string& givenAnswerId); //setzt die naechste Frage entsprechend der gegebenen antwortId 44 45 bool ending(const std::string& givenAnswerId); //ist true falls fuer die gegebene AntwortId keine Frage zur FragenId der Antwort existiert 46 47 const std::string& getQuestionString(); //gibt string der momentanen Frage 48 const std::string& getAnswerString(std::string answerId); //gibt string der zur Id passenden Frage 47 49 48 50 private: -
code/branches/Dialog_HS17/src/modules/dialog/DialogManager.cc
r11642 r11644 29 29 int DialogManager::getSize() 30 30 { 31 return 2; //returnthis->answerIds_->size();31 return this->answerIds_->size(); 32 32 } 33 33 … … 42 42 } 43 43 44 bool DialogManager::endtest() 45 { 46 return this->currentTalk_->ending(); 44 bool DialogManager::endtest(int index) 45 { 46 if(this->answerIds_->empty()) 47 { 48 return true; 49 } 50 else 51 { 52 return this->currentTalk_->ending(this->answerIds_->at(index)); 53 } 54 47 55 } 48 56 -
code/branches/Dialog_HS17/src/modules/dialog/DialogManager.h
r11642 r11644 22 22 DialogManager(); 23 23 24 24 //gibt lua den pointer auf den Manager 25 25 static DialogManager& getInstance() { return Singleton<DialogManager>::getInstance(); } //tolua_export 26 26 27 //setzt den momentanen Dialog auf den uebergebenen, wird vom Dialog verwendet um bei Trigger event sich selbst zu setzen 27 28 void setDialog(Dialog* dialog); 28 29 29 // from here on luafunctionality is declared30 //von hier an sind lua funktionalitaeten definiert 30 31 32 //gibt den string der momentanen Frage des Dialogs 31 33 std::string getQuestion(); //tolua_export 34 35 //gibt die laenge des Antwort-arrays der momentanen zuruek, 0 falls es leer ist 32 36 int getSize(); //tolua_export 37 38 //gibt den sting zu einer Frage im antwortarray der momentanen Frage 33 39 std::string getAnswer(int index); //tolua_export 40 41 //gibt den Namen der Person mit der man spricht 34 42 std::string getPerson(); //tolua_export 35 bool endtest(); //tolua_export 43 44 //testet ob der dialog weiter geht, true wenn es keine weitere Frage nach der Antwort kommt oder keine Antwort zur Frage existiert 45 bool endtest(int index); //tolua_export 46 47 //updated den Dialog so dass er auf die Antwort die im Antwortvector am index steht reagiert 36 48 void update(int index); //tolua_export 37 49 … … 40 52 41 53 Dialog* currentTalk_; 42 std::vector<std::string>* answerIds_;54 const std::vector<std::string>* answerIds_; 43 55 44 56 };//tolua_export -
code/branches/Dialog_HS17/src/modules/dialog/Question.cc
r11642 r11644 22 22 } 23 23 24 void Question::setQuestionId( std::stringId)24 void Question::setQuestionId(const std::string& Id) 25 25 { 26 26 this->questionId_ = Id; 27 27 } 28 28 29 std::string Question::getQuestionId()29 const std::string& Question::getQuestionId() const 30 30 { 31 31 return this->questionId_; 32 32 } 33 33 34 void Question::setQuestion( std::stringquestion)34 void Question::setQuestion(const std::string& question) 35 35 { 36 36 this->question_ = question; 37 37 } 38 38 39 std::string Question::getQuestion()39 const std::string& Question::getQuestion() const 40 40 { 41 41 return this->question_; … … 47 47 } 48 48 49 AnswerId* Question::getAnswerId(unsigned int index) const49 const AnswerId* Question::getAnswerId() const 50 50 { 51 51 return nullptr; 52 52 } 53 53 54 std::vector<std::string>* Question::getAnswerIds()54 const std::vector<std::string>* Question::getAnswerIds() 55 55 { 56 56 return &(this->answerIds_); -
code/branches/Dialog_HS17/src/modules/dialog/Question.h
r11642 r11644 20 20 virtual void XMLPort(Element& xmelement, XMLPort::Mode mode); 21 21 22 void setQuestionId( std::string Id);23 std::string getQuestionId();22 void setQuestionId(const std::string& Id); //xmlPort-Funktion, setzt Id 23 const std::string& getQuestionId() const; //xmlPort-Funktion, gibt Id string zuruek 24 24 25 void setQuestion( std::string question);26 std::string getQuestion();25 void setQuestion(const std::string& question); //xmlPort-Funktion, setzt Fragen string 26 const std::string& getQuestion() const; //xmlPort-Funktion, gibt Fragen string 27 27 28 void addAnswerId(AnswerId* answerId); //leer lassen um Dialog zu beenden29 AnswerId* getAnswerId(unsigned int index) const;28 void addAnswerId(AnswerId* answerId); //xmlPort-Funktion, nimmt AnswerIds von entsprechenden Objekten und fuegt sie in List ein. 29 const AnswerId* getAnswerId() const; //xmlPort-Funktion, gibt nichts zuruek 30 30 31 32 //braucht es getAnswerId oder reicht es andere funktion anzugeben, 33 // die sowieso gebraucht wird? 34 35 std::vector<std::string>* getAnswerIds(); //returnt vektor mit allen Ids 31 const std::vector<std::string>* getAnswerIds(); //returnt Pointer auf Vektor mit allen Ids 36 32 37 33
Note: See TracChangeset
for help on using the changeset viewer.