Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/tutorial2/src/libraries/util/Serialise.h @ 10241

Last change on this file since 10241 was 8706, checked in by dafrick, 13 years ago

Merging presentation branch back into trunk.
There are many new features and also a lot of other changes and bugfixes, if you want to know, digg through the svn log.
Not everything is yet working as it should, but it should be fairly stable. If you habe any bug reports, just send me an email.

  • Property svn:eol-style set to native
File size: 21.9 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Oliver Scheuss
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file
31    @ingroup Util
32    @brief Functions to serialise most of the types/classed used in Orxonox
33*/
34
35#ifndef _Serialise_H__
36#define _Serialise_H__
37
38#include "UtilPrereqs.h"
39
40#include <cstring>
41#include <set>
42#include "Math.h"
43#include "mbool.h"
44
45namespace orxonox{
46
47    /** @brief returns the size of the variable in a datastream */
48    template <class T> inline uint32_t returnSize( const T& variable );
49    /** @brief loads the value of a variable out of the bytestream and increases the mem pointer */
50    template <class T> inline void loadAndIncrease( const T& variable, uint8_t*& mem );
51    /** @brief saves the value of a variable into the bytestream and increases the mem pointer */
52    template <class T> inline void saveAndIncrease( const T& variable, uint8_t*& mem );
53    /** @brief checks whether the variable of type T is the same as in the bytestream */
54    template <class T> inline bool checkEquality( const T& variable, uint8_t* mem );
55
56
57  // =========== char*
58
59  inline uint32_t returnSize( char*& variable )
60  {
61    return strlen(variable)+1;
62  }
63
64  inline void saveAndIncrease( char*& variable, uint8_t*& mem )
65  {
66    strcpy((char*)mem, variable);
67    mem += returnSize(variable);
68  }
69
70  inline void loadAndIncrease( char*& variable, uint8_t*& mem )
71  {
72    if( variable )
73      delete variable;
74    uint32_t len = strlen((char*)mem)+1;
75    variable = new char[len];
76    strcpy((char*)variable, (char*)mem);
77    mem += len;
78  }
79
80  inline bool checkEquality( char*& variable, uint8_t* mem )
81  {
82    return strcmp(variable, (char*)mem)==0;
83  }
84
85// =================== Template specialisation stuff =============
86
87// =========== bool
88
89    template <> inline uint32_t returnSize( const bool& )
90    {
91        return sizeof(uint8_t);
92    }
93
94    template <> inline void loadAndIncrease( const bool& variable, uint8_t*& mem )
95    {
96        *(uint8_t*)( &variable ) = *static_cast<uint8_t*>(mem);
97        mem += returnSize( variable );
98    }
99
100    template <> inline void saveAndIncrease( const bool& variable, uint8_t*& mem )
101    {
102        *static_cast<uint8_t*>(mem) = *(uint8_t*)( &variable );
103        mem += returnSize( variable );
104    }
105
106    template <> inline bool checkEquality( const bool& variable, uint8_t* mem )
107    {
108        return *static_cast<uint8_t*>(mem) == *(uint8_t*)( &variable );
109    }
110
111// =========== char
112
113    template <> inline uint32_t returnSize( const char& )
114    {
115        return sizeof(uint8_t);
116    }
117
118    template <> inline void loadAndIncrease( const char& variable, uint8_t*& mem )
119    {
120        *(uint8_t*)( &variable ) = *static_cast<uint8_t*>(mem);
121        mem += returnSize( variable );
122    }
123
124    template <> inline void saveAndIncrease( const char& variable, uint8_t*& mem )
125    {
126        *static_cast<uint8_t*>(mem) = *(uint8_t*)( &variable );
127        mem += returnSize( variable );
128    }
129
130    template <> inline bool checkEquality( const char& variable, uint8_t* mem )
131    {
132        return *static_cast<uint8_t*>(mem) == *(uint8_t*)( &variable );
133    }
134
135// =========== unsigned char
136
137    template <> inline uint32_t returnSize( const unsigned char& )
138    {
139        return sizeof(uint8_t);
140    }
141
142    template <> inline void loadAndIncrease( const unsigned char& variable, uint8_t*& mem )
143    {
144        *(uint8_t*)( &variable ) = *static_cast<uint8_t*>(mem);
145        mem += returnSize( variable );
146    }
147
148    template <> inline void saveAndIncrease( const unsigned char& variable, uint8_t*& mem )
149    {
150        *static_cast<uint8_t*>(mem) = *(uint8_t*)( &variable );
151        mem += returnSize( variable );
152    }
153
154    template <> inline bool checkEquality( const unsigned char& variable, uint8_t* mem )
155    {
156        return *static_cast<uint8_t*>(mem) == *(uint8_t*)( &variable );
157    }
158
159// =========== short
160
161    template <> inline uint32_t returnSize( const short& )
162    {
163        return sizeof(int16_t);
164    }
165
166    template <> inline void loadAndIncrease( const short& variable, uint8_t*& mem )
167    {
168        *(short*)( &variable ) = *(int16_t*)(mem);
169        mem += returnSize( variable );
170    }
171
172    template <> inline void saveAndIncrease( const short& variable, uint8_t*& mem )
173    {
174        *(int16_t*)(mem) = variable;
175        mem += returnSize( variable );
176    }
177
178    template <> inline bool checkEquality( const short& variable, uint8_t* mem )
179    {
180        return *(int16_t*)(mem) == static_cast<int16_t>(variable);
181    }
182
183// =========== unsigned short
184
185    template <> inline uint32_t returnSize( const unsigned short& )
186    {
187        return sizeof(uint16_t);
188    }
189
190    template <> inline void loadAndIncrease( const unsigned short& variable, uint8_t*& mem )
191    {
192        *(unsigned short*)( &variable ) = *(uint16_t*)(mem);
193        mem += returnSize( variable );
194    }
195
196    template <> inline void saveAndIncrease( const unsigned short& variable, uint8_t*& mem )
197    {
198        *(uint16_t*)(mem) = variable;
199        mem += returnSize( variable );
200    }
201
202    template <> inline bool checkEquality( const unsigned short& variable, uint8_t* mem )
203    {
204        return *(uint16_t*)(mem) == variable;
205    }
206
207// =========== int
208
209    template <> inline uint32_t returnSize( const int& )
210    {
211        return sizeof(int32_t);
212    }
213
214    template <> inline void loadAndIncrease( const int& variable, uint8_t*& mem )
215    {
216        *(int *)( &variable ) = *(int32_t*)(mem);
217        mem += returnSize( variable );
218    }
219
220    template <> inline void saveAndIncrease( const int& variable, uint8_t*& mem )
221    {
222        *(int32_t*)(mem) = variable;
223        mem += returnSize( variable );
224    }
225
226    template <> inline bool checkEquality( const int& variable, uint8_t* mem )
227    {
228        return *(int32_t*)(mem) == variable;
229    }
230
231// =========== unsigned int
232
233    template <> inline uint32_t returnSize( const unsigned int& )
234    {
235        return sizeof(uint32_t);
236    }
237
238    template <> inline void loadAndIncrease( const unsigned int& variable, uint8_t*& mem )
239    {
240        *(unsigned int*)( &variable ) = *(uint32_t*)(mem);
241        mem += returnSize( variable );
242    }
243
244    template <> inline void saveAndIncrease( const unsigned int& variable, uint8_t*& mem )
245    {
246        *(uint32_t*)(mem) = variable;
247        mem += returnSize( variable );
248    }
249
250    template <> inline bool checkEquality( const unsigned int& variable, uint8_t* mem )
251    {
252        return *(uint32_t*)(mem) == variable;
253    }
254
255// =========== long
256
257    template <> inline uint32_t returnSize( const long& )
258    {
259        return sizeof(int32_t);
260    }
261
262    template <> inline void loadAndIncrease( const long& variable, uint8_t*& mem )
263    {
264        *(long*)( &variable ) = *(int32_t*)(mem);
265        mem += returnSize( variable );
266    }
267
268    template <> inline void saveAndIncrease( const long& variable, uint8_t*& mem )
269    {
270        *(int32_t*)(mem) = variable;
271        mem += returnSize( variable );
272    }
273
274    template <> inline bool checkEquality( const long& variable, uint8_t* mem )
275    {
276        return *(int32_t*)(mem) == variable;
277    }
278
279// =========== unsigned long
280
281    template <> inline uint32_t returnSize( const unsigned long& )
282    {
283        return sizeof(uint32_t);
284    }
285
286    template <> inline void loadAndIncrease( const unsigned long& variable, uint8_t*& mem )
287    {
288        *(unsigned long*)( &variable ) = *(uint32_t*)(mem);
289        mem += returnSize( variable );
290    }
291
292    template <> inline void saveAndIncrease( const unsigned long& variable, uint8_t*& mem )
293    {
294        *(uint32_t*)(mem) = variable;
295        mem += returnSize( variable );
296    }
297
298    template <> inline bool checkEquality( const unsigned long& variable, uint8_t* mem )
299    {
300        return *(uint32_t*)(mem) == variable;
301    }
302
303// =========== long long
304
305    template <> inline uint32_t returnSize( const long long& )
306    {
307        return sizeof(int64_t);
308    }
309
310    template <> inline void loadAndIncrease( const long long& variable, uint8_t*& mem )
311    {
312        *(long long*)( &variable ) = *(int64_t*)(mem);
313        mem += returnSize( variable );
314    }
315
316    template <> inline void saveAndIncrease( const long long& variable, uint8_t*& mem )
317    {
318        *(int64_t*)(mem) = variable;
319        mem += returnSize( variable );
320    }
321
322    template <> inline bool checkEquality( const long long& variable, uint8_t* mem )
323    {
324        return *(int64_t*)(mem) == variable;
325    }
326
327// =========== unsigned long long
328
329    template <> inline uint32_t returnSize( const unsigned long long& )
330    {
331        return sizeof(uint64_t);
332    }
333
334    template <> inline void loadAndIncrease( const unsigned long long& variable, uint8_t*& mem )
335    {
336        *(unsigned long long*)( &variable ) = *(uint64_t*)(mem);
337        mem += returnSize( variable );
338    }
339
340    template <> inline void saveAndIncrease( const unsigned long long& variable, uint8_t*& mem )
341    {
342        *(uint64_t*)(mem) = variable;
343        mem += returnSize( variable );
344    }
345
346    template <> inline bool checkEquality( const unsigned long long& variable, uint8_t* mem )
347    {
348        return *(uint64_t*)(mem) == variable;
349    }
350
351// =========== float
352
353    template <> inline uint32_t returnSize( const float& )
354    {
355        return sizeof(uint32_t);
356    }
357
358    template <> inline void loadAndIncrease( const float& variable, uint8_t*& mem )
359    {
360        *(uint32_t*)( &variable ) = *(uint32_t*)(mem);
361        mem += returnSize( variable );
362    }
363
364    template <> inline void saveAndIncrease( const float& variable, uint8_t*& mem )
365    {
366        *(uint32_t*)(mem) = *(uint32_t*)( &variable );
367        mem += returnSize( variable );
368    }
369
370    template <> inline bool checkEquality( const float& variable, uint8_t* mem )
371    {
372        return *(uint32_t*)(mem) == *(uint32_t*)( &variable );
373    }
374
375// =========== double
376
377    template <> inline uint32_t returnSize( const double& )
378    {
379        return sizeof(uint64_t);
380    }
381
382    template <> inline void loadAndIncrease( const double& variable, uint8_t*& mem )
383    {
384        *(uint64_t*)( &variable ) = *(uint64_t*)(mem);
385        mem += returnSize( variable );
386    }
387
388    template <> inline void saveAndIncrease( const double& variable, uint8_t*& mem )
389    {
390        *(uint64_t*)(mem) = *(uint64_t*)( &variable );
391        mem += returnSize( variable );
392    }
393
394    template <> inline bool checkEquality( const double& variable, uint8_t* mem )
395    {
396        return *(uint64_t*)(mem) == *(uint64_t*)( &variable );
397    }
398
399// =========== long double
400
401    template <> inline uint32_t returnSize( const long double& )
402    {
403        return sizeof(uint64_t);
404    }
405
406    template <> inline void loadAndIncrease( const long double& variable, uint8_t*& mem )
407    {
408        double temp;
409        memcpy(&temp, mem, sizeof(uint64_t));
410        *(long double*)( &variable ) = static_cast<long double>(temp);
411        mem += returnSize( variable );
412    }
413
414    template <> inline void saveAndIncrease( const long double& variable, uint8_t*& mem )
415    {
416        double temp = static_cast<double>(variable);
417        memcpy(mem, &temp, sizeof(uint64_t));
418        mem += returnSize( variable );
419    }
420
421    template <> inline bool checkEquality( const long double& variable, uint8_t* mem )
422    {
423        double temp = static_cast<double>(variable);
424        return memcmp(&temp, mem, sizeof(uint64_t))==0;
425    }
426
427// =========== string
428
429    template <> inline uint32_t returnSize( const std::string& variable )
430    {
431        return variable.length()+1;
432    }
433
434    template <> inline void saveAndIncrease( const std::string& variable, uint8_t*& mem )
435    {
436        memcpy(mem, variable.c_str(), variable.length()+1);
437        mem += variable.length()+1;
438    }
439
440    template <> inline void loadAndIncrease( const std::string& variable, uint8_t*& mem )
441    {
442        *(std::string*)( &variable ) = (const char *)mem;
443        mem += variable.length()+1;
444    }
445
446    template <> inline bool checkEquality( const std::string& variable, uint8_t* mem )
447    {
448        //return std::string((const char*)mem)==variable;
449        return (const char*)mem==variable;
450    }
451
452// =========== Degree
453
454    template <> inline uint32_t returnSize( const Degree& )
455    {
456        return sizeof(Ogre::Real);
457    }
458
459    template <> inline void saveAndIncrease( const Degree& variable, uint8_t*& mem )
460    {
461        Ogre::Real r = variable.valueDegrees();
462        memcpy(mem, &r, returnSize( variable ));
463        mem += returnSize( variable );
464    }
465
466    template <> inline void loadAndIncrease( const Degree& variable, uint8_t*& mem )
467    {
468        Ogre::Real* r = (Ogre::Real*)mem;
469        (Degree&)variable = *r;
470        mem += returnSize( variable );
471    }
472
473     template <> inline bool checkEquality( const Degree& variable, uint8_t* mem )
474    {
475        Ogre::Real* r = (Ogre::Real*)mem;
476        return variable==Degree(*r);
477    }
478
479// =========== Radian
480
481    template <> inline uint32_t returnSize( const Radian& )
482    {
483        return sizeof(Ogre::Real);
484    }
485
486    template <> inline void saveAndIncrease( const Radian& variable, uint8_t*& mem )
487    {
488        Ogre::Real r = variable.valueRadians();
489        memcpy(mem, &r, returnSize( variable ));
490        mem += returnSize( variable );
491    }
492
493    template <> inline void loadAndIncrease( const Radian& variable, uint8_t*& mem )
494    {
495        Ogre::Real* r = (Ogre::Real*)mem;
496        (Radian&)variable = *r;
497        mem += returnSize( variable );
498    }
499
500    template <> inline bool checkEquality( const Radian& variable, uint8_t* mem )
501    {
502        Ogre::Real* r = (Ogre::Real*)mem;
503        return variable==Degree(*r);
504    }
505
506    // =========== Vector2
507
508    template <> inline uint32_t returnSize( const Vector2& variable )
509    {
510        return returnSize( variable.x )+returnSize( variable.y );
511    }
512
513    template <> inline void saveAndIncrease( const Vector2& variable, uint8_t*& mem )
514    {
515        saveAndIncrease( variable.x, mem );
516        saveAndIncrease( variable.y, mem );
517    }
518
519    template <> inline void loadAndIncrease( const Vector2& variable, uint8_t*& mem )
520    {
521        loadAndIncrease( variable.x, mem );
522        loadAndIncrease( variable.y, mem );
523    }
524
525    template <> inline bool checkEquality( const Vector2& variable, uint8_t* mem )
526    {
527        return checkEquality(variable.x, mem) && checkEquality(variable.y, mem+returnSize(variable.x));
528    }
529
530    // =========== Vector3
531
532    template <> inline uint32_t returnSize( const Vector3& variable )
533    {
534        return returnSize( variable.x )+returnSize( variable.y )+returnSize( variable.z );
535    }
536
537    template <> inline void saveAndIncrease( const Vector3& variable, uint8_t*& mem )
538    {
539        saveAndIncrease( variable.x, mem );
540        saveAndIncrease( variable.y, mem );
541        saveAndIncrease( variable.z, mem );
542    }
543
544    template <> inline void loadAndIncrease( const Vector3& variable, uint8_t*& mem )
545    {
546        loadAndIncrease( variable.x, mem );
547        loadAndIncrease( variable.y, mem );
548        loadAndIncrease( variable.z, mem );
549    }
550
551    template <> inline bool checkEquality( const Vector3& variable, uint8_t* mem )
552    {
553        return checkEquality(variable.x, mem) && checkEquality(variable.y, mem+returnSize(variable.x)) &&
554            checkEquality(variable.z, mem+returnSize(variable.x)+returnSize(variable.y));
555    }
556
557    // =========== Vector4
558
559    template <> inline uint32_t returnSize( const Vector4& variable )
560    {
561        return returnSize( variable.w )+returnSize( variable.x )+returnSize( variable.y )+returnSize( variable.z );
562    }
563
564    template <> inline void saveAndIncrease( const Vector4& variable, uint8_t*& mem )
565    {
566        saveAndIncrease( variable.w, mem );
567        saveAndIncrease( variable.x, mem );
568        saveAndIncrease( variable.y, mem );
569        saveAndIncrease( variable.z, mem );
570    }
571
572    template <> inline void loadAndIncrease( const Vector4& variable, uint8_t*& mem )
573    {
574        loadAndIncrease( variable.w, mem );
575        loadAndIncrease( variable.x, mem );
576        loadAndIncrease( variable.y, mem );
577        loadAndIncrease( variable.z, mem );
578    }
579
580    template <> inline bool checkEquality( const Vector4& variable, uint8_t* mem )
581    {
582        return checkEquality(variable.w, mem) && checkEquality(variable.x, mem+returnSize(variable.w)) &&
583            checkEquality(variable.y, mem+returnSize(variable.w)+returnSize(variable.x)) &&
584            checkEquality(variable.z, mem+returnSize(variable.w)+returnSize(variable.x)+returnSize(variable.y));
585    }
586
587    // =========== Quaternion
588
589    template <> inline uint32_t returnSize( const Quaternion& variable )
590    {
591        return returnSize( variable.w )+returnSize( variable.x )+returnSize( variable.y )+returnSize( variable.z );
592    }
593
594    template <> inline void saveAndIncrease( const Quaternion& variable, uint8_t*& mem )
595    {
596        saveAndIncrease( variable.w, mem );
597        saveAndIncrease( variable.x, mem );
598        saveAndIncrease( variable.y, mem );
599        saveAndIncrease( variable.z, mem );
600    }
601
602    template <> inline void loadAndIncrease( const Quaternion& variable, uint8_t*& mem )
603    {
604        loadAndIncrease( variable.w, mem );
605        loadAndIncrease( variable.x, mem );
606        loadAndIncrease( variable.y, mem );
607        loadAndIncrease( variable.z, mem );
608    }
609
610    template <> inline bool checkEquality( const Quaternion& variable, uint8_t* mem )
611    {
612        return checkEquality(variable.w, mem) && checkEquality(variable.x, mem+returnSize(variable.w)) &&
613            checkEquality(variable.y, mem+returnSize(variable.w)+returnSize(variable.x)) &&
614            checkEquality(variable.z, mem+returnSize(variable.w)+returnSize(variable.x)+returnSize(variable.y));
615    }
616
617    // =========== ColourValue
618
619    template <> inline uint32_t returnSize( const ColourValue& variable )
620    {
621        return returnSize( variable.r )+returnSize( variable.g )+returnSize( variable.b )+returnSize( variable.a );
622    }
623
624    template <> inline void saveAndIncrease( const ColourValue& variable, uint8_t*& mem )
625    {
626        saveAndIncrease( variable.r, mem );
627        saveAndIncrease( variable.g, mem );
628        saveAndIncrease( variable.b, mem );
629        saveAndIncrease( variable.a, mem );
630    }
631
632    template <> inline void loadAndIncrease( const ColourValue& variable, uint8_t*& mem )
633    {
634        loadAndIncrease( variable.r, mem );
635        loadAndIncrease( variable.g, mem );
636        loadAndIncrease( variable.b, mem );
637        loadAndIncrease( variable.a, mem );
638    }
639
640    template <> inline bool checkEquality( const ColourValue& variable, uint8_t* mem )
641    {
642        return checkEquality(variable.r, mem) && checkEquality(variable.g, mem+returnSize(variable.r)) &&
643            checkEquality(variable.b, mem+returnSize(variable.r)+returnSize(variable.g)) &&
644            checkEquality(variable.a, mem+returnSize(variable.r)+returnSize(variable.g)+returnSize(variable.b));
645    }
646
647    // =========== mbool
648
649    template <> inline uint32_t returnSize( const mbool& variable )
650    {
651        return returnSize( (unsigned char&)((mbool&)variable).getMemory() );
652    }
653
654    template <> inline void saveAndIncrease( const mbool& variable, uint8_t*& mem )
655    {
656        saveAndIncrease( (unsigned char&)((mbool&)variable).getMemory(), mem );
657    }
658
659    template <> inline void loadAndIncrease( const mbool& variable, uint8_t*& mem )
660    {
661        loadAndIncrease( (unsigned char&)((mbool&)variable).getMemory(), mem );
662    }
663
664    template <> inline bool checkEquality( const mbool& variable, uint8_t* mem )
665    {
666        return checkEquality( (unsigned char&)((mbool&)variable).getMemory(), mem );
667    }
668
669    // =========== std::set
670
671    template <class T> inline uint32_t returnSize( const std::set<T>& variable )
672    {
673        uint32_t tempsize = sizeof(uint32_t); // for the number of entries
674        for( typename std::set<T>::iterator it=((std::set<T>*)(&variable))->begin(); it!=((std::set<T>*)(&variable))->end(); ++it)
675            tempsize += returnSize( *it );
676        return tempsize;
677    }
678
679    template <class T> inline void saveAndIncrease(  const std::set<T>& variable, uint8_t*& mem )
680    {
681        typename std::set<T>::const_iterator it = variable.begin();
682        saveAndIncrease( (uint32_t)variable.size(), mem );
683        for( ; it!=variable.end(); ++it )
684            saveAndIncrease( *it, mem );
685    }
686
687    template <class T> inline void loadAndIncrease(std::set<T>& variable, uint8_t*& mem )
688    {
689        uint32_t nrOfElements = 0;
690        loadAndIncrease( nrOfElements, mem );
691        typename std::set<T>::iterator it = variable.begin();
692        for( uint32_t i = 0; i<nrOfElements; ++i )
693        {
694            T temp;
695            loadAndIncrease(temp, mem);
696            while( it!=variable.end() && *it!=temp )
697            {
698                variable.erase(it++);
699                ++it;
700            }
701            if( it==variable.end() )
702            {
703                variable.insert(temp);
704            }
705        }
706    }
707
708    template <class T> inline bool checkEquality( const std::set<T>& variable, uint8_t* mem )
709    {
710        uint8_t* temp = mem;
711        uint32_t nrOfElements;
712        loadAndIncrease(nrOfElements, mem);
713        if( variable.size() == nrOfElements )
714        {
715            T tempT;
716            for( uint32_t i=0; i<nrOfElements; ++i )
717            {
718                loadAndIncrease(tempT, mem);
719                if( variable.find(tempT) == variable.end() )
720                {
721                    mem = temp;
722                    return false;
723                }
724            }
725        }
726        else
727        {
728            mem = temp;
729            return false;
730        }
731        return true;
732    }
733}
734
735
736#endif
Note: See TracBrowser for help on using the repository browser.