source: cpp/frams/model/modelparts.h @ 1095

Last change on this file since 1095 was 1039, checked in by Maciej Komosinski, 4 years ago

Removed Part's "visual thickness" property

  • Property svn:eol-style set to native
File size: 19.2 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[920]2// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[109]4
5#ifndef _MODELPARTS_H_
6#define _MODELPARTS_H_
7
8#include <frams/util/3d.h>
[121]9#include <frams/genetics/genoconv.h>
[109]10
11#include <frams/util/extvalue.h>
12#include <frams/util/list.h>
13#include <frams/util/sstring.h>
14#include <frams/util/sstringutils.h>
15#include <frams/param/param.h>
16#include <frams/param/syntparam.h>
17#include <frams/util/usertags.h>
18#include <frams/param/paramtabobj.h>
19
20#include <stdio.h>
21
22class Model;
23class IRange;
24class MultiRange;
25
[899]26typedef UserTags<Model, void *, 5> ModelUserTags;
[109]27
[934]28
29/// Introduced only because we can't have a forward declaration of enum in the Model class,
30/// and we would need a forward declaration because of mutual (cyclic) dependence of declarations of Model and NeuroClass.
31/// https://stackoverflow.com/questions/27019292/is-in-class-enum-forward-declaration-possible
32/// Use Model::... instead of ModelEnum::...
33class ModelEnum
34{
35public:
[999]36        enum ShapeType {
37                SHAPETYPE_BALL_AND_STICK = 0, SHAPETYPE_SOLIDS = 1, SHAPETYPE_UNKNOWN, SHAPETYPE_ILLEGAL, ///< 0 and 1 have special significance - these values allow for bit operations.
38                SHAPETYPE_FIRST = SHAPETYPE_BALL_AND_STICK, SHAPETYPE_LAST = SHAPETYPE_SOLIDS // for iteration
39        };
[934]40};
41
[109]42/** Common base for model elements. */
43class PartBase
44{
45public:
[714]46        SString vis_style;
[899]47        PartBase(const SString &s) :vis_style(s), mapped(0) {}
[714]48        ~PartBase();
[899]49        static SString getDefaultStyle() { return SString("none"); }
[714]50        MultiRange *mapped;
51        enum PartBaseFlags { Selected = 1 };
52        int flags;
53        Model *owner;   ///< backlink to the model
[109]54
[714]55        SString info;
[109]56
[714]57        Model &getModel() const { return *owner; }
[109]58
[714]59        ModelUserTags userdata;
[109]60
[714]61        void notifyMappingChange();
[109]62
[714]63        void clearMapping();
[899]64        MultiRange *getMapping() { return mapped; }
[714]65        void setMapping(const IRange &mr);
66        void addMapping(const IRange &mr);
67        void setMapping(const MultiRange &mr);
68        void addMapping(const MultiRange &mr);
[109]69
[899]70        void setInfo(const SString &name, const SString &value);
71        void setInfo(const SString &name, int value);
72        void setInfo(const SString &name, double value);
73        SString getInfo(const SString &name);
[109]74};
75
[999]76/// Part is the only real physical object in creatures in Framsticks.
[109]77/// You can use this class for querying and adjusting constructed
[999]78/// model properties.
[714]79class Part : public PartBase
[109]80{
[714]81        friend class Model;
82        static SString getDefaultStyle();
83        Part(double _mass, double _size, double _density, double _friction, double _ingest, double _assim)
84                :PartBase(getDefaultStyle()), mass(_mass), size(_size), density(_density), friction(_friction), ingest(_ingest), assim(_assim)
[109]85        {}
[714]86        void defassign();
[109]87public:
[714]88        // base properties - have special meaning and therefore are often accessed directly for convenience
89        Pt3D p;    ///< 3d coordinates of the part
90        Orient o;  ///< orientation in 3d space (rotation matrix)
91        /// ParamInterface object is preferred way to get/set other properties.
92        Param extraProperties();
93        Param properties();
94        paInt refno;
95        Pt3D rot;///< rotation angles
[109]96
[714]97        ///
98        paInt shape;///default=old Framsticks compatible, do not mix with shapes>0
[999]99        enum Shape {
100                SHAPE_BALL = 0, ///<  for "ball and stick" shape type model only.
101                SHAPE_ELLIPSOID = 1, SHAPE_CUBOID = 2, SHAPE_CYLINDER = 3,
102                SHAPE_FIRST = SHAPE_BALL, SHAPE_LAST = SHAPE_CYLINDER // for iteration
[977]103        };
104        static const char* getShapeName(Shape sh);
105
[714]106        double mass, size, density, friction, ingest, assim, hollow;
107        Pt3D scale;
108        Pt3D food;
109        //SList points; // collistion points
110        //Slist neurons; // "select * from owner->neurons where part=this" ;-)
[109]111
[714]112        Pt3D vcolor;
[109]113
[999]114        Part(enum Shape s = SHAPE_BALL);
[899]115        Part(const Part &src) :PartBase(getDefaultStyle()) { operator=(src); }
116        void operator=(const Part &src);
[109]117
[714]118        void setPositionAndRotationFromAxis(const Pt3D &p1, const Pt3D &p2);
119        void setOrient(const Orient &o);///< set part.o and calculates part.rot (rotation angles)
120        void setRot(const Pt3D &r);///< set part.rot (rotation angles) and calculate part.o
[109]121
[899]122        static Param &getStaticParam();
[109]123};
124
[934]125class Part_MinMaxDef : public Part //contains additional information for Model::getMinPart()/getMaxPart()/getDefPart()
126{
127public:
128        double volume; ///< Introduced to limit the range of volumes (~mass) in simulation of solids. Genetic operators should observe this min,max volume by calculating and limiting the volume of Parts based on their type and sx,sy,sz.
129
130        void defassign();
131        Part_MinMaxDef() { defassign(); }
132};
133
[109]134/// Imaginary connection between two parts.
135/// Joint has no mass nor intertia but can transfer forces.
[714]136class Joint : public PartBase
[109]137{
[714]138        friend class Model;
139        SString getDefaultStyle();
140        Joint(double _stamina, double _stif, double _rotstif, double _d)
141                :PartBase(getDefaultStyle()), stamina(_stamina), stif(_stif), rotstif(_rotstif)
142        {
143                d = Pt3D(_d, 0, 0);
144        }
145        void defassign();
146        void resetDeltaMarkers();
[109]147public:
[714]148        // base properties:
149        paInt p1_refno, p2_refno; ///< parts' reference numbers
[109]150
[714]151        Part *part1, *part2;    ///< references to parts
152        class Pt3D d;           ///< position delta between parts
153        class Pt3D rot; ///< orientation delta between parts expressed as 3 angles
[932]154        enum Shape {
[999]155                SHAPE_STICK = 0, ///<  for "ball and stick" shape type model, creates a physical (cylinder or cuboid) rod between parts. Do not mix with part.shape>0.
[932]156                SHAPE_FIXED = 1, ///< merge parts into one physical entity
157                SHAPE_HINGE_X = 2, ///< hinge connection, revolving around X axis defined by hinge_pos and hinge_rot
[977]158                SHAPE_HINGE_XY = 3, ///< double hinge connection, revolving around X and Y axes defined by hinge_pos and hinge_rot
[999]159                SHAPE_FIRST = SHAPE_STICK, SHAPE_LAST = SHAPE_HINGE_XY // for iteration
[932]160        };
[915]161        paInt shape;///< values of type Shape (paInt for integration with Param)
[977]162        static const char* getShapeName(Shape sh);
[915]163        class Pt3D hinge_pos; ///< hinge position (relative to part1) for HINGE_X and HINGE_XY
164        class Pt3D hinge_rot; ///< hinge orientation (relative to part1) for HINGE_X and HINGE_XY
165        double hinge_limit_x[2], hinge_limit_y[2]; ///< hinge movement range - i.e., extreme allowed values of a state. A state can be an angle or other physical property. limit[0] <= 0 <= limit[1]. Relative Part position and orientation as set in the Model define the initial state 0.
[109]166
[714]167        Joint();
[899]168        Joint(const Joint &src) :PartBase(getDefaultStyle()) { operator=(src); }
169        void operator=(const Joint &src);
[109]170
[714]171        /** connect two parts with this joint.
172                p2 position will be adjusted if delta option is in effect.
173                @see isDelta()
174                */
[899]175        void attachToParts(Part *p1, Part *p2);
[714]176        /// @see attachToParts(Part*,Part*)
177        void attachToParts(int p1, int p2);
[109]178
[714]179        /** discard delta information but don't disable delta flag.
180                delta will be calculated from parts positions during final consistency check.
181                */
182        void resetDelta();
[109]183
[714]184        /** enable or disable delta option.
185                delta value is not changed.
186                */
187        void useDelta(bool use);
[109]188
[714]189        /** @return true if delta option is in effect.
190                @see useDelta(), resetDelta(), useDelta()
191                */
192        bool isDelta();
[109]193
[714]194        /// ParamInterface object is preferred way to get/set other properties.
195        Param extraProperties();
196        Param properties();
[109]197
[714]198        // do not touch these:
199        paInt refno; ///< this joint's reference number
200        double stamina;
201        double stif, rotstif;   ///< stiffness for moving and bending forces
202        class Orient o; ///< orientation delta between parts as rotation matrix
203        /** flag: generated f0 should include delta data.
204                set by 'singlestep' if j: attributes use delta option */
205        bool usedelta;
206        Pt3D vcolor;
[109]207
[899]208        static Param &getStaticParam();
[109]209};
210
211#define JOINT_DELTA_MARKER 99999.0
212
213
[899]214
215////////////////// Neural Network /////////////////
216
[109]217class NeuroClass;
218
[899]219typedef UserTags<NeuroClass, void *, 5> NeuroClassUserTags;
[109]220
221/** Information about neuron class.
222 */
223class NeuroClass
224{
[714]225        bool ownedvectordata;
[899]226        void operator=(const NeuroClass &nosuchthich) {}
[714]227public:
228        SString name, longname, description;
229        ParamEntry *props;
230        bool ownedprops;//< destructor will free props using ParamObject::freeParamTab
231        paInt prefinputs, prefoutput;
232        paInt preflocation;
[932]233
[999]234        enum PrefLocation { PREFER_UNATTACHED = 0, PREFER_PART = 1, PREFER_JOINT = 2 };
235
236        static constexpr int SUPPORTED_SHAPETYPE_BALL_AND_STICK = 1;
237        static constexpr int SUPPORTED_SHAPETYPE_SOLIDS = 2;
238        static constexpr int SUPPORTED_SHAPETYPE_ALL = SUPPORTED_SHAPETYPE_BALL_AND_STICK | SUPPORTED_SHAPETYPE_SOLIDS;
[932]239        paInt supported_shape_types; //< bitfield of 'Model::shape' values: NeuroClass::SUPPORTED_SHAPE_xxx = 1 << Model::SHAPE_xxx
[975]240
[1004]241        static constexpr int SUPPORTED_JOINT_STICK = 1;
[975]242        static constexpr int SUPPORTED_JOINT_FIXED = 2;
243        static constexpr int SUPPORTED_JOINT_HINGE_X = 4;
244        static constexpr int SUPPORTED_JOINT_HINGE_XY = 8;
[1004]245        static constexpr int SUPPORTED_JOINTSHAPE_ALL = SUPPORTED_JOINT_STICK + SUPPORTED_JOINT_FIXED + SUPPORTED_JOINT_HINGE_X + SUPPORTED_JOINT_HINGE_XY;
[977]246        paInt supported_joint_shapes; //< bitfield of 'Joint::shape' values: NeuroClass::SUPPORTED_JOINT_xxx = 1 << JOINT::SHAPE_xxx
[975]247
[714]248        int *vectordata;
249        paInt visualhints;
[109]250
[714]251        //void *impl;
252        int impl_count;
253        bool active;
254        bool genactive;
255        NeuroClassUserTags userdata;
[109]256
[714]257        //////////////////////
258        ~NeuroClass();
259        NeuroClass();
260        NeuroClass(ParamEntry *_props, SString _description,
[999]261                int _prefinputs, int _prefoutput, int _preflocation, int *_vectordata, bool own_vd = 1, int vhints = 0, int sup_shapes = NeuroClass::SUPPORTED_SHAPETYPE_ALL, int sup_joints = NeuroClass::SUPPORTED_JOINTSHAPE_ALL);
[714]262        /** class name for use in Neuro::setClassName(), Neuro::setDetails() (former 'moredata' field),
263                eg. "N","-",G" */
[899]264        const SString &getName() { return name; }
[714]265        /** human friendly name, eg. "Neuron","Link","Gyroscope"  */
[899]266        const SString &getLongName() { return longname; }
[714]267        /** long description */
[899]268        const SString &getDescription() { return description; }
269        ParamEntry *getParamTab() { return props; }
[109]270
[714]271        /** NeuroClass specific properties, recognized by all neurons of this class */
272        Param getProperties() { return Param(props); }
[109]273
[714]274        /** preferred number of inputs, -1 = no preference (any number will go).
275                extra inputs may be ignored by the object (depends on the class).
276                */
277        int getPreferredInputs() { return (int)prefinputs; }
[109]278
[714]279        /** @return 0 if this object doesn't provide useful output signal. */
280        int getPreferredOutput() { return (int)prefoutput; }
[109]281
[978]282        /** @return 0 (PREFER_UNATTACHED) if the neuron doesn't need any assignment to a body element.
283                @return 1 (PREFER_PART) if the neuron likes to be attached to a Part ( @see Neuro::attachToPart() )
284                @return 2 (PREFER_JOINT) if the neuron prefers to be attached to a Joint ( @see Neuro::attachToJoint() )
[714]285                */
[997]286        PrefLocation getPreferredLocation() { return (PrefLocation)preflocation; }
[714]287        /** vector drawing to be used in neuro net diagram.
288                interpretation:
289                {
290                LEN = datalength (excluding this number)
291                NL = number_of_lines
292                line#1 ->  NS = number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1,
293                ...
294                line#NL -> NS = number_of_segments, x1,y1, x2,y2, ... xNS-1,yNS-1,
295                }
296                */
[932]297        int getSupportedShapeTypes() { return (int)supported_shape_types; }
[934]298        bool isShapeTypeSupported(ModelEnum::ShapeType t) { return (1 << (int)t) & supported_shape_types; }
[977]299        int getSupportedJointShapes() { return (int)supported_joint_shapes; }
300        bool isJointShapeSupported(Joint::Shape t) { return (1 << (int)t) & supported_joint_shapes; }
[899]301        int *getSymbolGlyph()
[714]302        {
303                return vectordata;
304        }
305        void setSymbolGlyph(int *data, bool owned = 1)
306        {
[899]307                if (vectordata && ownedvectordata) delete[]vectordata;
[714]308                vectordata = data; ownedvectordata = owned;
309        }
310        /** additional information about how the neuron should be drawn
311                used by structure view (and maybe some other components).
312                return value is defined by the enum Hint
313                @see enum Hint
314                */
315        int getVisualHints()
316        {
317                return (int)visualhints;
318        }
[109]319
[714]320        enum Hint
[738]321        {
[714]322                /** don't draw neurons of this class */
323                Invisible = 1,
324                /** don't draw classname label below the neuron */
325                DontShowClass = 2,
326                /** draw the neuron at the first part when attached to joint (default is in the middle) */
327                AtFirstPart = 4,
328                /** draw the neuron at the second part when attached to joint (default is in the middle) */
329                AtSecondPart = 8,
330                /** use effector colour for this neuro unit */
331                EffectorClass = 16,
332                /** use receptor colour for this neuro unit */
333                ReceptorClass = 32,
[937]334                IsV1BendMuscle = 64,
335                IsV1RotMuscle = 128,
336                IsLinearMuscle = 256,
337                IsSolidMuscle = 512
[714]338        };
[109]339
[714]340        /** textual summary, automatically generated from other properties (like the neuro class tooltip) */
341        SString getSummary();
342
343        static void resetActive(); ///< set default values of active and genactive for all classes
[899]344        static void setGenActive(const char *classes[]); ///< set genactive for specified classes
[109]345};
346
347
[899]348
349
350
351
352/** Single processing unit in Framsticks neural network.  */
[714]353class Neuro : public PartBase
[109]354{
[714]355        friend class Model;
356        static SString getDefaultStyle();
[109]357
[714]358        struct NInput {
359                Neuro *n; double weight; SString *info;
360                NInput(Neuro *_n, double w, SString *i = 0) :n(_n), weight(w), info(i) {}
361        };
[109]362
[714]363        SListTempl<NInput> inputs;
[109]364
[714]365        NeuroClass *myclass;
366        bool knownclass;
367        SString myclassname, myclassparams;
368        /** set myclass and make knownclass=true */
369        void checkClass();
[899]370        SString **inputInfo(int i);
[714]371        void defassign();
[109]372
373public:
[714]374        enum NeuroFlags { HoldState = 2 };
375        Param properties();
376        Param extraProperties();
[109]377
[899]378        void setInputInfo(int i, const SString &name, const SString &value);
379        void setInputInfo(int i, const SString &name, int value);
380        void setInputInfo(int i, const SString &name, double value);
[714]381        SString getInputInfo(int i);
[899]382        SString getInputInfo(int i, const SString &name);
[109]383
[899]384        NeuroClass *getClass();
385        void setClass(NeuroClass *);
[109]386
[714]387        SString getClassParams() { return myclassparams; }
[899]388        void setClassParams(const SString &cp) { myclassparams = cp; }
[109]389
[714]390        SString getClassName();
[899]391        void setClassName(const SString &clazz);
[109]392
[714]393        /** return neuro unit details encoded as <CLASS> ":" <PROPERTIES>
[109]394
[714]395                new Neuro can be created as root object (without parent) or can be
396                the child of existing Neuro. Children of the Neuro are its inputs.
397                Standard Framsticks neuron calculates the sum of all input units - other processing
398                units don't have to treat them equally and can even ignore some of them.
399                There are hints about expected inputs in the class database, @see getClass
[109]400
[714]401                Application should not assume anything about classes and its properties
402                except for two standard classes: (information about all current classes
403                can be retrieved with getClass/getClassProperties methods)
404                - getClassName()="N" is the standard Framsticks neuron, accepts any number of inputs,
405                compatible with old Neuro object
406                - getClassName()="-" is the neuron link, compatible with old Neuro-Neuro link
407                (NeuroItem with empty details)
408                Empty details defaults to "-" if the parent unit is specified,
409                and "N" if the unit has no parent.
410                */
411        SString getDetails();
[109]412
[714]413        /** details = classname + ":" + classparams
414                @see getDetails()
415                */
[899]416        void setDetails(const SString &);
[714]417
[109]418#define STATRICKCLASS Neuro
[714]419        PARAMGETDEF(details) { arg1->setString(getDetails()); }
420        PARAMSETDEF(details) { setDetails(arg1->getString()); return PSET_CHANGED; }
421        PARAMGETDEF(inputCount);
422        PARAMPROCDEF(p_getInputNeuroDef);
423        PARAMPROCDEF(p_getInputNeuroIndex);
424        PARAMPROCDEF(p_getInputWeight);
425        PARAMGETDEF(classObject);
[109]426#undef STATRICKCLASS
427
[714]428        ///@param handle_defaults_when_saving see SyntParam
429        SyntParam classProperties(bool handle_defaults_when_saving = true);
430        // base properties:
431        paInt refno; ///< unique reference number (former 'neuro' refno)
[109]432
[714]433        paInt part_refno; ///< can be used by some items as the part ref#
434        paInt joint_refno; ///< can be used by some items as the joint ref#
[109]435
[714]436        Pt3D pos, rot;  ///< default = zero
[109]437
[714]438        ModelUserTags userdata;
[109]439
[714]440        Neuro();
441        Neuro(double _state, double _inertia, double _force, double _sigmo);
[899]442        Neuro(const Neuro &src) :PartBase(getDefaultStyle()) { operator=(src); }
[109]443
[714]444        ~Neuro();
[109]445
[899]446        void operator=(const Neuro &src);
[109]447
[714]448        /** Attach this Neuro to the specified Part or detach it from the body if p==NULL.
449                Neuro can be attached to either Part or Joint, but not both.
450                @see getPart()
451                */
[899]452        void attachToPart(Part *p) { part = p; joint = 0; }
[109]453
[714]454        /** Attach this Neuro to the specified Joint or detach it from the body if p==NULL.
455                Neuro can be attached to either Part or Joint, but not both.
456                @see getJoint()
457                */
[899]458        void attachToJoint(Joint *j) { joint = j; part = 0; }
[109]459
[714]460        void attachToPart(int i);
461        void attachToJoint(int i);
[109]462
[714]463        /** @return Part the Neuro is attached to, or NULL if it has no defined location on the body.
464                @see attachToPart()
465                */
466        Part *getPart() { return part; }
[109]467
[714]468        /** @return Joint the Neuro is attached to, or NULL if it has no defined location on the body.
469                @see attachToJoint()
470                */
471        Joint *getJoint() { return joint; }
[109]472
[714]473        int isOldEffector();
474        int isOldReceptor();
475        int isOldNeuron();
476        int isNNConnection();
[109]477
[714]478        /** @return the number of inputs connected to this Neuro.
479                Functions like getInput(), getInputWeight() will accept connection number [0..InputCount-1]
480                */
481        int getInputCount() const { return inputs.size(); }
[109]482
[714]483        /// @return the number of output connections (including possible self-connections)
484        int getOutputsCount() const;
[109]485
[714]486        /** @return the Neuro connected as i-th input */
[899]487        Neuro *getInput(int i) const { return (i >= inputs.size()) ? 0 : inputs(i).n; }
[714]488        /** @return the Neuro connected as i-th input.
489                @param weight
490                */
[899]491        Neuro *getInput(int i, double &weight) const;
[714]492        /** @return connectin weight for i-th input */
493        double getInputWeight(int i) const;
494        /** change connection weight for i-th input */
495        void setInputWeight(int i, double weight);
496        /** connect i-th input with another neuron */
[899]497        void setInput(int i, Neuro *n);
[714]498        /** connect i-th input with another neuron */
[899]499        void setInput(int i, Neuro *n, double weight);
[714]500        /** add new input. @return its reference number */
[899]501        int addInput(Neuro *child, double weight = 1.0, const SString *info = 0);
[714]502        /** @return reference number [0..InputCount-1] of the input
503           or -1 if 'child' is not connected with this Neuro.*/
[899]504        int findInput(Neuro *child) const;
[714]505        void removeInput(paInt refno);
506        /**    @return reference number of the child connection, like findInput() */
[899]507        int removeInput(Neuro *child);
[109]508
[899]509        int findInputs(SList &result, const char *classname = 0, const Part *part = 0, const Joint *joint = 0) const;
510        int findOutputs(SList &result, const char *classname = 0, const Part *part = 0, const Joint *joint = 0) const;
[109]511
[714]512        /* class database retrieval */
513        static int getClassCount();
514        /** @return Neuro class name.
515                @param classindex 0 .. getClassCount()
516                */
517        static SString getClassName(int classindex);
[899]518        static NeuroClass *getClass(int classindex);
519        static NeuroClass *getClass(const SString &classname);
520        static int getClassIndex(const NeuroClass *nc);
[109]521
[714]522        // not really private, but you should not access those directly
523        double state;
[109]524
[714]525        /** may reference parent neuron if parentcount is exacty 1. parent is invalid otherwise. @sa parentcount */
526        Neuro *parent;
527        int parentcount; ///< @sa parent
[109]528
[714]529        Part *part;     ///< link to the Part
530        Joint *joint;   ///< link to the Joint - required by some objects (eg.muscles)
531        Orient o;       ///< rotation matrix calculated from "rot"
532        static ParamEntry emptyParamTab[];
[899]533        static Param &getStaticParam();
[109]534};
535
[714]536class NeuroExt : public Neuro
[109]537{
[714]538public:
[109]539#define STATRICKCLASS NeuroExt
[714]540        PARAMGETDEF(neuroclass);
541        PARAMSETDEF(neuroclass);
[952]542        PARAMGETDEF(liveNeuro);
[109]543#undef STATRICKCLASS
[714]544        static ParamEntry *getParamTab();
[109]545};
546
547class NeuroConn
548{
[714]549        void defassign();
550public:
551        int n1_refno, n2_refno;
552        double weight;
553        SString info;
554        NeuroConn();
[109]555};
556
[934]557extern ParamEntry f0_part_paramtab[], f0_part_minmaxdef_paramtab[], f0_joint_paramtab[], f0_nodeltajoint_paramtab[], f0_neuro_paramtab[], f0_neuroconn_paramtab[], f0_neuroitem_paramtab[];
[109]558
559#endif
Note: See TracBrowser for help on using the repository browser.