From 84aaf322f9d9bd6e05c002f87fe381ccad0c876b Mon Sep 17 00:00:00 2001
From: Dhruva Gowda Storz <dhruvastorz@gmail.com>
Date: Tue, 19 Dec 2017 15:54:13 +0530
Subject: [PATCH] Recovered rdesigneur tutorial. Modified file by adding
 extended contents, commented out incomplete sections. Modified rdesigneur
 snippets page title to 'more rdesigneur examples' instead of just
 'Rdesigneur'

---
 docs/source/user/py/cookbook/Rd.rst         | 1188 +++++++++++++++++++
 docs/source/user/py/cookbook/multi_rdes.rst |    6 +-
 docs/source/user/py/cookbook/multiscale.rst |    4 +
 3 files changed, 1195 insertions(+), 3 deletions(-)
 create mode 100644 docs/source/user/py/cookbook/Rd.rst

diff --git a/docs/source/user/py/cookbook/Rd.rst b/docs/source/user/py/cookbook/Rd.rst
new file mode 100644
index 00000000..04836369
--- /dev/null
+++ b/docs/source/user/py/cookbook/Rd.rst
@@ -0,0 +1,1188 @@
+**Rdesigneur: Building multiscale models**
+==========================================
+
+.. Upi Bhalla
+
+.. Aug 26 2016.
+
+.. --------------
+
+Contents
+--------
+
+.. contents::
+   :depth: 3
+
+Introduction
+------------
+
+**Rdesigneur** (Reaction Diffusion and Electrical SIGnaling in NEURons)
+is an interface to the multiscale modeling capabilities in MOOSE. It is
+designed to build models incorporating biochemical signaling pathways in
+dendrites and spines, coupled to electrical events in neurons.
+Rdesigneur assembles models from predefined parts: it delegates the
+details to specialized model definition formats. Rdesigneur combines one
+or more of the following cell parts to build models:
+
+-  Neuronal morphology
+-  Dendritic spines
+-  Ion channels
+-  Reaction systems
+
+Rdesigneur's main role is to specify how these are put together,
+including assigning parameters to do so. Rdesigneur also helps with
+setting up the simulation input and output.
+
+Quick Start
+-----------
+
+Here we provide a few use cases, building up from a minimal model to a
+reasonably complete multiscale model spanning chemical and electrical
+signaling.
+
+Bare Rdesigneur: single passive compartment
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If we don't provide any arguments at all to the Rdesigneur, it makes a
+model with a single passive electrical compartment in the MOOSE path
+``/model/elec/soma``. Here is how to do this:
+
+::
+
+    import moose
+    import rdesigneur as rd
+    rdes = rd.rdesigneur()
+    rdes.buildModel()
+
+To confirm that it has made a compartment with some default values we
+can add a line:
+
+::
+
+    moose.showfields( rdes.soma )
+
+This should produce the output:
+
+::
+
+    [ /model[0]/elec[0]/soma[0] ]
+    diameter         = 0.0005
+    fieldIndex       = 0
+    Ra               = 7639437.26841
+    y0               = 0.0
+    Rm               = 424413.177334
+    index            = 0
+    numData          = 1
+    inject           = 0.0
+    initVm           = -0.065
+    Em               = -0.0544
+    y                = 0.0
+    numField         = 1
+    path             = /model[0]/elec[0]/soma[0]
+    dt               = 0.0
+    tick             = -2
+    z0               = 0.0
+    name             = soma
+    Cm               = 7.85398163398e-09
+    x0               = 0.0
+    Vm               = -0.06
+    className        = ZombieCompartment
+    idValue          = 465
+    length           = 0.0005
+    Im               = 1.3194689277e-08
+    x                = 0.0005
+    z                = 0.0
+
+Simulate and display current pulse to soma
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A more useful script would run and display the model. Rdesigneur can
+help with the stimulus and the plotting. This simulation has the same
+passive compartment, and current is injected as the simulation runs.
+This script displays the membrane potential of the soma as it charges
+and discharges.
+
+::
+
+    import moose
+    import rdesigneur as rd
+    rdes = rd.rdesigneur(
+        stimList = [['soma', '1', '.', 'inject', '(t>0.1 && t<0.2) * 2e-8']],
+        plotList = [['soma', '1', '.', 'Vm', 'Soma membrane potential']],
+    )
+    rdes.buildModel()
+    moose.reinit()
+    moose.start( 0.3 )
+    rdes.display()
+
+The *stimList* defines a stimulus. Each entry has five arguments:
+
+::
+
+    `[region_in_cell, region_expression, moose_object, parameter, expression_string]`
+
+-  ``region_in_cell`` specifies the objects to stimulate. Here it is
+   just the soma.
+-  ``region_expression`` specifies a geometry based calculation to
+   decide whether to apply the stimulus. The value must be >0 for the
+   stimulus to be present. Here it is just 1. ``moose_object`` specifies
+   the simulation object to operate upon during the stimulus. Here the
+   ``.`` means that it is the soma itself. In other models it might be a
+   channel on the soma, or a synapse, and so on.
+-  ``parameter`` specifies the simulation parameter on the moose object
+   that the stimulus will modify. Here it is the injection current to
+   the soma compartment.
+-  ``expression_string`` calculates the value of the parameter,
+   typically as a function of time. Here we use the function
+   ``(t>0.1 && t<0.2) * 2e-8`` which evaluates as 2e-8 between the times
+   of 0.1 and 0.2 seconds.
+
+To summarise this, the *stimList* here means *inject a current of 20nA
+to the soma between the times of 0.1 and 0.2 s*.
+
+The *plotList* defines what to plot. It has a similar set of arguments:
+
+::
+
+    `[region_in_cell, region_expression, moose_object, parameter, title_of_plot]`
+
+These mean the same thing as for the stimList except for the title of
+the plot.
+
+The *rdes.display()* function causes the plots to be displayed.
+
+.. figure:: ../../../../images/rdes2_passive_squid.png
+   :alt: Plot for current input to passive compartment
+
+   Plot for current input to passive compartment
+
+When we run this we see an initial depolarization as the soma settles
+from its initial -65 mV to a resting Em = -54.4 mV. These are the
+original HH values, see the example above. At t = 0.1 seconds there is
+another depolarization due to the current injection, and at t = 0.2
+seconds this goes back to the resting potential.
+
+HH Squid model in a single compartment
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here we put the Hodgkin-Huxley squid model channels into a passive
+compartment. The HH channels are predefined as prototype channels for
+Rdesigneur,
+
+::
+
+    import moose
+    import pylab
+    import rdesigneur as rd
+    rdes = rd.rdesigneur(
+        chanProto = [['make_HH_Na()', 'Na'], ['make_HH_K()', 'K']],
+        chanDistrib = [
+            ['Na', 'soma', 'Gbar', '1200' ],
+            ['K', 'soma', 'Gbar', '360' ]],
+        stimList = [['soma', '1', '.', 'inject', '(t>0.1 && t<0.2) * 1e-8' ]],
+        plotList = [['soma', '1', '.', 'Vm', 'Membrane potential']]
+    )
+
+    rdes.buildModel()
+    moose.reinit()
+    moose.start( 0.3 )
+    rdes.display()
+
+Here we introduce two new model specification lines:
+
+-  **chanProto**: This specifies which ion channels will be used in the
+   model. Each entry here has two fields: the source of the channel
+   definition, and (optionally) the name of the channel. In this example
+   we specify two channels, an Na and a K channel using the original
+   Hodgkin-Huxley parameters. As the source of the channel definition we
+   use the name of the Python function that builds the channel. The
+   *make\_HH\_Na()* and *make\_HH\_K()* functions are predefined but we
+   can also specify our own functions for making prototypes. We could
+   also have specified the channel prototype using the name of a channel
+   definition file in ChannelML (a subset of NeuroML) format.
+-  **chanDistrib**: This specifies *where* the channels should be placed
+   over the geometry of the cell. Each entry in the chanDistrib list
+   specifies the distribution of parameters for one channel using four
+   entries:
+
+   ``[object_name, region_in_cell, parameter, expression_string]``
+
+   In this case the job is almost trivial, since we just have a single
+   compartment named *soma*. So the line
+
+   ``['Na', 'soma', 'Gbar', '1200' ]``
+
+   means *Put the Na channel in the soma, and set its maximal
+   conductance density (Gbar) to 1200 Siemens/m^2*.
+
+As before we apply a somatic current pulse. Since we now have HH
+channels in the model, this generates action potentials.
+
+.. figure:: ../../../../images/rdes3_squid.png
+   :alt: Plot for HH squid simulation
+
+   Plot for HH squid simulation
+
+HH Squid model in an axon
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here we put the Hodgkin-Huxley squid model into a long compartment that
+is subdivided into many segments, so that we can watch action potentials
+propagate. Most of this example is boilerplate code to build a spiral
+axon. There is a short *rdesigneur* segment that takes the spiral axon
+prototype and populates it with channels, and sets up the display. Later
+examples will show you how to read morphology files to specify the
+neuronal geometry.
+
+::
+
+    import numpy as np
+    import moose
+    import pylab
+    import rdesigneur as rd
+
+    numAxonSegments = 200
+    comptLen = 10e-6
+    comptDia = 1e-6
+    RM = 1.0
+    RA = 10.0
+    CM = 0.01
+
+    def makeAxonProto():
+            axon = moose.Neuron( '/library/axon' )
+            prev = rd.buildCompt( axon, 'soma', RM = RM, RA = RA, CM = CM, dia = 10e-6, x=0, dx=comptLen)
+            theta = 0
+            x = comptLen
+            y = 0.0
+
+            for i in range( numAxonSegments ):
+                dx = comptLen * np.cos( theta )
+                dy = comptLen * np.sin( theta )
+                r = np.sqrt( x * x + y * y )
+                theta += comptLen / r
+                compt = rd.buildCompt( axon, 'axon' + str(i), RM = RM, RA = RA, CM = CM, x = x, y = y, dx = dx, dy = dy, dia = comptDia )
+                moose.connect( prev, 'axial', compt, 'raxial' )
+                prev = compt
+                x += dx
+                y += dy
+            
+            return axon
+
+    moose.Neutral( '/library' )
+    makeAxonProto()
+
+    rdes = rd.rdesigneur(
+            chanProto = [['make_HH_Na()', 'Na'], ['make_HH_K()', 'K']],
+            cellProto = [['elec','axon']],
+            chanDistrib = [
+                ['Na', '#', 'Gbar', '1200' ],
+                ['K', '#', 'Gbar', '360' ]],
+            stimList = [['soma', '1', '.', 'inject', '(t>0.01 && t<0.2) * 2e-11' ]],
+            plotList = [['soma', '1', '.', 'Vm', 'Membrane potential']],
+            moogList = [['#', '1', '.', 'Vm', 'Vm (mV)']]
+            )
+
+    rdes.buildModel()
+    moose.reinit()
+
+    rdes.displayMoogli( 0.00005, 0.05, 0.0 )
+
+.. figure:: ../../../../images/rdes3.1_axon.png
+   :alt: Axon with propagating action potential
+
+   Axon with propagating action potential
+
+Note how we explicitly create the prototype axon on '/library', and then
+specify it using the *cellProto* line in the rdesigneur. The moogList
+specifies the 3-D display. See below for how to set up and use these
+displays.
+
+HH Squid model in a myelinated axon
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is a curious cross-species chimera model, where we embed the HH
+equations into a myelinated example model. As for the regular axon
+above, most of the example is boilerplate setup code. Note how we
+restrict the HH channels to the nodes of Ranvier using a conditional
+test for the diameter of the axon segment.
+
+::
+
+    import numpy as np
+    import moose
+    import pylab
+    import rdesigneur as rd
+
+    numAxonSegments = 405
+    nodeSpacing = 100
+    comptLen = 10e-6
+    comptDia = 2e-6 # 2x usual
+    RM = 100.0 # 10x usual
+    RA = 5.0
+    CM = 0.001 # 0.1x usual
+
+    nodeDia = 1e-6
+    nodeRM = 1.0
+    nodeCM = 0.01
+
+    def makeAxonProto():
+        axon = moose.Neuron( '/library/axon' )
+        x = 0.0
+        y = 0.0
+        prev = rd.buildCompt( axon, 'soma', RM = RM, RA = RA, CM = CM, dia = 10e-6, x=0, dx=comptLen)
+        theta = 0
+        x = comptLen
+
+        for i in range( numAxonSegments ):
+            r = comptLen
+            dx = comptLen * np.cos( theta )
+            dy = comptLen * np.sin( theta )
+            r = np.sqrt( x * x + y * y )
+            theta += comptLen / r
+            if i % nodeSpacing == 0:
+                compt = rd.buildCompt( axon, 'axon' + str(i), RM = nodeRM, RA = RA, CM = nodeCM, x = x, y = y, dx = dx, dy = dy, dia = nodeDia )
+            else:
+                compt = rd.buildCompt( axon, 'axon' + str(i), RM = RM, RA = RA, CM = CM, x = x, y = y, dx = dx, dy = dy, dia = comptDia )
+            moose.connect( prev, 'axial', compt, 'raxial' )
+            prev = compt
+            x += dx
+            y += dy
+        
+        return axon
+
+    moose.Neutral( '/library' )
+    makeAxonProto()
+
+    rdes = rd.rdesigneur(
+        chanProto = [['make_HH_Na()', 'Na'], ['make_HH_K()', 'K']],
+        cellProto = [['elec','axon']],
+        chanDistrib = [
+            ['Na', '#', 'Gbar', '12000 * (dia < 1.5e-6)' ],
+            ['K', '#', 'Gbar', '3600 * (dia < 1.5e-6)' ]],
+        stimList = [['soma', '1', '.', 'inject', '(t>0.01 && t<0.2) * 1e-10' ]],
+        plotList = [['soma,axon100,axon200,axon300,axon400', '1', '.', 'Vm', 'Membrane potential']],
+        moogList = [['#', '1', '.', 'Vm', 'Vm (mV)']]
+    )
+
+    rdes.buildModel()
+
+    for i in moose.wildcardFind( "/model/elec/#/Na" ):
+        print i.parent.name, i.Gbar
+
+    moose.reinit()
+
+    rdes.displayMoogli( 0.00005, 0.05, 0.0 )
+
+When you run the example, keep an eye out for a few things:
+
+-  **saltatory conduction:** This is the way the action potential jumps
+   from one node of Ranvier to the next. Between the nodes it is just
+   passive propagation.
+-  **Failure to propagate:** Observe that the second and fourth action
+   potentials fails to trigger propagation along the axon. Here we have
+   specially tuned the model properties so that this happens. With a
+   larger RA of 10.0, the model will be more reliable.
+-  **Speed:** Compare the propagation speed with the previous,
+   unmyelinated axon. Note that the current model is larger!
+
+.. figure:: ../../../../images/rdes3.2_myelinated_axon.png
+   :alt: Myelinated axon with propagating action potential
+
+   Myelinated axon with propagating action potential
+
+Reaction system in a single compartment
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here we use the compartment as a place in which to embed a chemical
+model. The chemical oscillator model is predefined in the rdesigneur
+prototypes.
+
+::
+
+    import moose
+    import pylab
+    import rdesigneur as rd
+    rdes = rd.rdesigneur(
+            turnOffElec = True,
+            diffusionLength = 1e-3, # Default diffusion length is 2 microns
+            chemProto = [['makeChemOscillator()', 'osc']],
+            chemDistrib = [['osc', 'soma', 'install', '1' ]],
+            plotList = [['soma', '1', 'dend/a', 'conc', 'a Conc'],
+                ['soma', '1', 'dend/b', 'conc', 'b Conc']]
+    )
+    rdes.buildModel()
+    b = moose.element( '/model/chem/dend/b' )
+    b.concInit *= 5
+    moose.reinit()
+    moose.start( 200 )
+
+    rdes.display()
+
+In this special case we set the turnOffElec flag to True, so that
+Rdesigneur only sets up chemical and not electrical calculations. This
+makes the calculations much faster, since we disable electrical
+calculations and delink chemical calculations from them.
+
+We also have a line which sets the ``diffusionLength`` to 1 mm, so that
+it is bigger than the 0.5 mm squid axon segment in the default
+compartment. If you don't do this the system will subdivide the
+compartment into the default 2 micron voxels for the purposes of putting
+in a reaction-diffusion system. We discuss this case below.
+
+Note how the *plotList* is done here. To remind you, each entry has five
+arguments
+
+::
+
+    [region_in_cell, region_expression, moose_object, parameter, title_of_plot]
+
+The change from the earlier usage is that the ``moose_object`` now
+refers to a chemical entity, in this example the molecule *dend/a*. The
+simulator builds a default chemical compartment named *dend* to hold the
+reactions defined in the *chemProto*. What we do in this plot is to
+select molecule *a* sitting in *dend*, and plot its concentration. Then
+we do this again for molecule *b*.
+
+After the model is built, we add a couple of lines to change the initial
+concentration of the molecular pool *b*. Note its full path within
+MOOSE: */model/chem/dend/b*. It is scaled up 5x to give rise to slowly
+decaying oscillations.
+
+.. figure:: ../../../../images/rdes4_osc.png
+   :alt: Plot for single-compartment reaction simulation
+
+   Plot for single-compartment reaction simulation
+
+Reaction-diffusion system
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to see what a reaction-diffusion system looks like, delete the
+``diffusionLength`` expression in the previous example and add a couple
+of lines to set up 3-D graphics for the reaction-diffusion product:
+
+::
+
+    import moose
+    import pylab
+    import rdesigneur as rd
+    rdes = rd.rdesigneur(
+            turnOffElec = True,
+            chemProto = [['makeChemOscillator()', 'osc']],
+            chemDistrib = [['osc', 'soma', 'install', '1' ]],
+            plotList = [['soma', '1', 'dend/a', 'conc', 'Concentration of a'],
+                ['soma', '1', 'dend/b', 'conc', 'Concentration of b']],
+            moogList = [['soma', '1', 'dend/a', 'conc', 'a Conc', 0, 360 ]]
+    )
+
+    rdes.buildModel()
+    bv = moose.vec( '/model/chem/dend/b' )
+    bv[0].concInit *= 2
+    bv[-1].concInit *= 2
+    moose.reinit()
+
+    rdes.displayMoogli( 1, 400, 0.001 )
+
+This is the line we deleted.
+
+::
+
+        diffusionLength = 1e-3,
+
+With this change we permit *rdesigneur* to use the default diffusion
+length of 2 microns. The 500-micron axon segment is now subdivided into
+250 voxels, each of which has a reaction system and diffusing molecules.
+To make it more picturesque, we have added a line after the plotList, to
+display the outcome in 3-D:
+
+::
+
+    moogList = [['soma', '1', 'dend/a', 'conc', 'a Conc', 0, 360 ]]
+
+This line says: take the model compartments defined by ``soma`` as the
+region to display, do so throughout the the geometry (the ``1``
+signifies this), and over this range find the chemical entity defined by
+``dend/a``. For each ``a`` molecule, find the ``conc`` and dsiplay it.
+There are two optional arguments, ``0`` and ``360``, which specify the
+low and high value of the displayed variable.
+
+In order to initially break the symmetry of the system, we change the
+initial concentration of molecule b at each end of the cylinder:
+
+::
+
+    bv[0].concInit *= 2
+    bv[-1].concInit *= 2
+
+If we didn't do this the entire system would go through a few cycles of
+decaying oscillation and then reach a boring, spatially uniform, steady
+state. Try putting an initial symmetry break elsewhere to see what
+happens.
+
+To display the concenctration changes in the 3-D soma as the simulation
+runs, we use the line
+
+::
+
+    `rdes.displayMoogli( 1, 400, 0.001 )`
+
+The arguments mean: *displayMoogli( frametime, runtime, rotation )*
+Here,
+
+::
+
+    frametime = time by which simulation advances between display updates
+    runtime = Total simulated time
+    rotation = angle by which display rotates in each frame, in radians.
+
+When we run this, we first get a 3-D display with the oscillating
+reaction-diffusion system making its way inward from the two ends. After
+the simulation ends the plots for all compartments for the whole run
+come up.
+
+.. figure:: ../../../../images/rdes5_reacdiff.png
+   :alt: Display for oscillatory reaction-diffusion simulation
+
+   Display for oscillatory reaction-diffusion simulation
+
+Primer on using the 3-D MOOGLI display
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here is a short primer on the 3-D display controls.
+
+-  *Roll, pitch, and yaw*: Use the letters *r*, *p*, and *y*. To rotate
+   backwards, use capitals.
+-  *Zoom out and in*: Use the *,* and *.* keys, or their upper-case
+   equivalents, *<* and *>*. Easier to remember if you think in terms of
+   the upper-case.
+-  *Left/right/up/down*: Arrow keys.
+-  *Quit*: control-q or control-w.
+-  You can also use the mouse or trackpad to control most of the above.
+-  By default rdesigneur gives Moogli a small rotation each frame. It is
+   the *rotation* argument in the line:
+
+   ``displayMoogli( frametime, runtime, rotation )``
+
+These controls operate over and above this rotation, but the rotation
+continues. If you set the rotation to zero you can, with a suitable
+flick of the mouse, get the image to rotate in any direction you choose
+as long as the window is updating.
+
+Make a toy multiscale model with electrical and chemical signaling.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now we put together chemical and electrical models. In this toy model we
+have an HH-squid type single compartment electrical model, cohabiting
+with a chemical oscillator. The chemical oscillator regulates K+ channel
+amounts, and the average membrane potential regulates the amounts of a
+reactant in the chemical oscillator. This is a recipe for some strange
+firing patterns.
+
+::
+
+    import moose
+    import pylab
+    import rdesigneur as rd
+    rdes = rd.rdesigneur(
+            # We want just one compartment so we set diffusion length to be
+            # bigger than the 0.5 mm HH axon compartment default. 
+                diffusionLength = 1e-3,
+                chanProto = [['make_HH_Na()', 'Na'], ['make_HH_K()', 'K']],
+                chanDistrib = [
+                    ['Na', 'soma', 'Gbar', '1200' ],
+                    ['K', 'soma', 'Gbar', '360' ]],
+            chemProto = [['makeChemOscillator()', 'osc']],
+            chemDistrib = [['osc', 'soma', 'install', '1' ]],
+            # These adaptor parameters give interesting-looking but
+            # not particularly physiological behaviour.
+            adaptorList = [
+                [ 'dend/a', 'conc', 'Na', 'modulation', 1, -5.0 ],
+                [ 'dend/b', 'conc', 'K', 'modulation', 1, -0.2],
+                [ 'dend/b', 'conc', '.', 'inject', -1.0e-7, 4e-7 ],
+                [ '.', 'Vm', 'dend/s', 'conc', 2.5, 20.0 ]
+            ],
+            plotList = [['soma', '1', 'dend/a', 'conc', 'a Conc'],
+                ['soma', '1', 'dend/b', 'conc', 'b Conc'],
+                ['soma', '1', 'dend/s', 'conc', 's Conc'],
+                ['soma', '1', 'Na', 'Gk', 'Na Gk'],
+                ['soma', '1', '.', 'Vm', 'Membrane potential']
+        ]
+    )
+
+    rdes.buildModel()
+    moose.reinit()
+    moose.start( 250 ) # Takes a few seconds to run this.
+
+    rdes.display()
+
+We've already modeled the HH squid model and the oscillator
+individually, and you should recognize the parts of those models above.
+The new section that makes this work the *adaptorList* which specifies
+how the electrical and chemical parts talk to each other. This entirely
+fictional set of interactions goes like this:
+
+::
+
+    [ 'dend/a', 'conc', 'Na', 'modulation', 1, -5.0 ]
+
+-  *dend/a*: The originating variable comes from the 'a' pool on the
+   'dend' compartment.
+
+   *conc*: This is the originating variable name on the 'a' pool.
+
+   *Na*: This is the target variable
+
+   *modulation*: scale the Gbar of Na up and down. Use 'modulation'
+   rather than direct assignment of Gbar since Gbar is different for
+   each differently-sized compartment.
+
+   *1*: This is the initial offset
+
+   *-5.0*: This is the scaling from the input to the parameter updated
+   in the simulation.
+
+A similar set of adaptor entries couple the molecule *dend/b* to the K
+channel, *dend/b* again to the current injection into the soma, and the
+membrane potential to the concentration of *dend/s*.
+
+.. figure:: ../../../../images/rdes6_multiscale.png
+   :alt: Plot for toy multiscale model
+
+   Plot for toy multiscale model
+
+Morphology: Load .swc morphology file and view it
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here we build a passive model using a morphology file in the .swc file
+format (as used by NeuroMorpho.org). The morphology file is predefined
+for Rdesigneur and resides in the directory ``./cells``. We apply a
+somatic current pulse, and view the somatic membrane potential in a
+plot, as before. To make things interesting we display the morphology in
+3-D upon which we represent the membrane potential as colors.
+
+::
+
+    import moose
+    import rdesigneur as rd
+    rdes = rd.rdesigneur(
+        cellProto = [['./cells/h10.CNG.swc', 'elec']],
+        stimList = [['soma', '1', '.', 'inject', 't * 25e-9' ]], 
+        plotList = [['#', '1', '.', 'Vm', 'Membrane potential'],
+            ['#', '1', 'Ca_conc', 'Ca', 'Ca conc (uM)']],
+        moogList = [['#', '1', '.', 'Vm', 'Soma potential']]
+    )
+
+    rdes.buildModel()
+
+    moose.reinit()
+    rdes.displayMoogli( 0.0002, 0.1 )
+
+Here the new concept is the cellProto line, which loads in the specified
+cell model:
+
+::
+
+    `[ filename, cellname ]`
+
+The system recognizes the filename extension and builds a model from the
+swc file. It uses the cellname **elec** in this example.
+
+We use a similar line as in the reaction-diffusion example, to build up
+a Moogli display of the cell model:
+
+::
+
+    `moogList = [['#', '1', '.', 'Vm', 'Soma potential']]`
+
+Here we have:
+
+::
+
+    *#*: the path to use for selecting the compartments to display. 
+    This wildcard means use all compartments.
+    *1*: The expression to use for the compartments. Again, `1` means use
+    all of them.
+    *.*: Which object in the compartment to display. Here we are using the
+    compartment itself, so it is just a dot.
+    *Vm*: Field to display
+    *Soma potential*: Title for display.
+
+.. figure:: ../../../../images/rdes7_passive.png
+   :alt: 3-D display for passive neuron
+
+   3-D display for passive neuron
+
+Build an active neuron model by putting channels into a morphology file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We load in a morphology file and distribute voltage-gated ion channels
+over the neuron. Here the voltage-gated channels are obtained from a
+number of channelML files, located in the ``./channels`` subdirectory.
+Since we have a spatially extended neuron, we need to specify the
+spatial distribution of channel densities too.
+
+::
+
+    import moose
+    import rdesigneur as rd
+    rdes = rd.rdesigneur(
+        chanProto = [
+            ['./chans/hd.xml'],
+            ['./chans/kap.xml'],
+            ['./chans/kad.xml'],
+            ['./chans/kdr.xml'],
+            ['./chans/na3.xml'],
+            ['./chans/nax.xml'],
+            ['./chans/CaConc.xml'],
+            ['./chans/Ca.xml']
+        ],
+        cellProto = [['./cells/h10.CNG.swc', 'elec']],
+        chanDistrib = [ \
+            ["hd", "#dend#,#apical#", "Gbar", "50e-2*(1+(p*3e4))" ],
+            ["kdr", "#", "Gbar", "p < 50e-6 ? 500 : 100" ],
+            ["na3", "#soma#,#dend#,#apical#", "Gbar", "850" ],
+            ["nax", "#soma#,#axon#", "Gbar", "1250" ],
+            ["kap", "#axon#,#soma#", "Gbar", "300" ],
+            ["kap", "#dend#,#apical#", "Gbar",
+                "300*(H(100-p*1e6)) * (1+(p*1e4))" ],
+            ["Ca_conc", "#", "tau", "0.0133" ],
+            ["kad", "#soma#,#dend#,#apical#", "Gbar", "50" ],
+            ["Ca", "#", "Gbar", "50" ]
+        ],
+        stimList = [['soma', '1', '.', 'inject', '(t>0.02) * 1e-9' ]],
+        plotList = [['#', '1', '.', 'Vm', 'Membrane potential'],
+                ['#', '1', 'Ca_conc', 'Ca', 'Ca conc (uM)']],
+        moogList = [['#', '1', 'Ca_conc', 'Ca', 'Calcium conc (uM)', 0, 120],
+            ['#', '1', '.', 'Vm', 'Soma potential']]
+    )
+
+    rdes.buildModel()
+
+    moose.reinit()
+    rdes.displayMoogli( 0.0002, 0.052 )
+
+Here we make more extensive use of two concepts which we've already seen
+from the single compartment squid model:
+
+1. *chanProto*: This defines numerous channels, each of which is of the
+   form:
+
+   ``[ filename ]``
+
+   or
+
+   ``[ filename, channelname ]``
+
+If the *channelname* is not specified the system uses the last part of
+the channel name, before the filetype suffix.
+
+2. *chanDistrib*: This defines the spatial distribution of each channel
+   type. Each line is of a form that should be familiar now:
+
+   ``[channelname, region_in_cell, parameter, expression_string]``
+
+-  The *channelname* is the name of the prototype from *chanproto*. This
+   is usually an ion channel, but in the example above you can also see
+   a calcium concentration pool defined.
+-  The *region\_in\_cell* is typically defined using wildcards, so that
+   it generalizes to any cell morphology. For example, the plain
+   wildcard ``#`` means to consider all cell compartments. The wildcard
+   ``#dend#`` means to consider all compartments with the string
+   ``dend`` somewhere in the name. Wildcards can be comma-separated, so
+   ``#soma#,#dend#`` means consider all compartments with either soma or
+   dend in their name. The naming in MOOSE is defined by the model file.
+   Importantly, in **.swc** files MOOSE generates names that respect the
+   classification of compartments into axon, soma, dendrite, and apical
+   dendrite compartments respectively. SWC files generate compartment
+   names such as:
+
+   ::
+
+       soma_<number>
+       dend_<number>
+       apical_<number>
+       axon_<number>
+
+where the number is automatically assigned by the reader. In order to
+select all dendritic compartments, for example, one would use *"#dend#"*
+where the *"#"* acts as a wildcard to accept any string. - The
+*parameter* is usually Gbar, the channel conductance density in *S/m^2*.
+If *Gbar* is zero or less, then the system economizes by not
+incorporating this channel mechanism in this part of the cell.
+Similarly, for calcium pools, if the *tau* is below zero then the
+calcium pool object is simply not inserted into this part of the cell. -
+The *expression\_string* defines the value of the parameter, such as
+Gbar. This is typically a function of position in the cell. The
+expression evaluator knows about several parameters of cell geometry.
+All units are in metres:
+
+-  *x*, *y* and *z* coordinates.
+-  *g*, the geometrical distance from the soma
+-  *p*, the path length from the soma, measured along the dendrites.
+-  *dia*, the diameter of the dendrite.
+-  *L*, The electrotonic length from the soma (no units).
+
+Along with these geometrical arguments, we make liberal use of the
+Heaviside function H(x) to set up the channel distributions. The
+expression evaluator also knows about pretty much all common algebraic,
+trignometric, and logarithmic functions, should you wish to use these.
+
+Also note the two Moogli displays. The first is the calcium
+concentration. The second is the membrane potential in each compartment.
+Easy!
+
+.. figure:: ../../../../images/rdes8_active.png
+   :alt: 3-D display for active neuron
+
+   3-D display for active neuron
+
+Build a spiny neuron from a morphology file and put active channels in it.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This model is one step elaborated from the previous one, in that we now
+also have dendritic spines. MOOSE lets one decorate a bare neuronal
+morphology file with dendritic spines, specifying various geometric
+parameters of their location. As before, we use an swc file for the
+morphology, and the same ion channels and distribution.
+
+::
+
+    import moose
+    import pylab
+    import rdesigneur as rd
+    rdes = rd.rdesigneur(
+        chanProto = [
+            ['./chans/hd.xml'],
+            ['./chans/kap.xml'],
+            ['./chans/kad.xml'],
+            ['./chans/kdr.xml'],
+            ['./chans/na3.xml'],
+            ['./chans/nax.xml'],
+            ['./chans/CaConc.xml'],
+            ['./chans/Ca.xml']
+        ],
+        cellProto = [['./cells/h10.CNG.swc', 'elec']],
+        spineProto = [['makeActiveSpine()', 'spine']],
+        chanDistrib = [
+            ["hd", "#dend#,#apical#", "Gbar", "50e-2*(1+(p*3e4))" ],
+            ["kdr", "#", "Gbar", "p < 50e-6 ? 500 : 100" ],
+            ["na3", "#soma#,#dend#,#apical#", "Gbar", "850" ],
+            ["nax", "#soma#,#axon#", "Gbar", "1250" ],
+            ["kap", "#axon#,#soma#", "Gbar", "300" ],
+            ["kap", "#dend#,#apical#", "Gbar",
+                "300*(H(100-p*1e6)) * (1+(p*1e4))" ],
+            ["Ca_conc", "#", "tau", "0.0133" ],
+            ["kad", "#soma#,#dend#,#apical#", "Gbar", "50" ],
+            ["Ca", "#", "Gbar", "50" ]
+        ],
+        spineDistrib = [['spine', '#dend#,#apical#', '20e-6', '1e-6']],
+        stimList = [['soma', '1', '.', 'inject', '(t>0.02) * 1e-9' ]],
+        plotList = [['#', '1', '.', 'Vm', 'Membrane potential'],
+                ['#', '1', 'Ca_conc', 'Ca', 'Ca conc (uM)']],
+        moogList = [['#', '1', 'Ca_conc', 'Ca', 'Calcium conc (uM)', 0, 120],
+            ['#', '1', '.', 'Vm', 'Soma potential']]
+    )
+
+    rdes.buildModel()
+
+    moose.reinit()
+    rdes.displayMoogli( 0.0002, 0.023 )
+
+Spines are set up in a familiar way: we first define one (or more)
+prototype spines, and then distribute these around the cell. Here is the
+prototype string:
+
+::
+
+        [spine_proto, spinename]
+
+*spineProto*: This is typically a function. One can define one's own,
+but there are several predefined ones in rdesigneur. All these define a
+spine with the following parameters:
+
+-  head diameter 0.5 microns
+-  head length 0.5 microns
+-  shaft length 1 micron
+-  shaft diameter of 0.2 microns
+-  RM = 1.0 ohm-metre square
+-  RA = 1.0 ohm-meter
+-  CM = 0.01 Farads per square metre.
+
+Here are the predefined spine prototypes:
+
+-  *makePassiveSpine()*: This just makes a passive spine with the
+   default parameters
+-  *makeExcSpine()*: This makes a spine with NMDA and glu receptors, and
+   also a calcium pool. The NMDA channel feeds the Ca pool.
+-  *makeActiveSpine()*: This adds a Ca channel to the exc\_spine. and
+   also a calcium pool.
+
+The spine distributions are specified in a familiar way for the first
+few arguments, and then there are multiple (optional) spine-specific
+parameters:
+
+*[spinename, region\_in\_cell, spacing, spacing\_distrib, size,
+size\_distrib, angle, angle\_distrib ]*
+
+Only the first two arguments are mandatory.
+
+-  *spinename*: The prototype name
+-  *region\_in\_cell*: Usual wildcard specification of names of
+   compartments in which to put the spines.
+-  *spacing*: Math expression to define spacing between spines. In the
+   current implementation this evaluates to
+   ``1/probability_of_spine_per_unit_length``. Defaults to 10 microns.
+   Thus, there is a 10% probability of a spine insertion in every
+   micron. This evaluation method has the drawback that it is possible
+   to space spines rather too close to each other. If spacing is zero or
+   less, no spines are inserted.
+-  *spacing\_distrib*: Math expression for distribution of spacing. In
+   the current implementation, this specifies the interval at which the
+   system samples from the spacing probability above. Defaults to 1
+   micron.
+-  *size*: Linear scale factor for size of spine. All dimensions are
+   scaled by this factor. The default spine head here is 0.5 microns in
+   diameter and length. If the scale factor were to be 2, the volume
+   would be 8 times as large. Defaults to 1.0.
+-  *size\_distrib*: Range for size of spine. A random number R is
+   computed in the range 0 to 1, and the final size used is
+   ``size + (R - 0.5) * size_distrib``. Defaults to 0.5
+-  *angle*: This specifies the initial angle at which the spine sticks
+   out of the dendrite. If all angles were zero, they would all point
+   away from the soma. Defaults to 0 radians.
+-  *angle\_distrib*: Specifies a random number to add to the initial
+   angle. Defaults to 2 PI radians, so the spines come out in any
+   direction.
+
+One may well ask why we are not using a Python dictionary to handle all
+these parameters. Short answer is: terseness. Longer answer is that the
+rdesigneur format is itself meant to be an intermediate form for an
+eventual high-level, possibly XML-based multiscale modeling format.
+
+.. figure:: ../../../../images/rdes9_spiny_active.png
+   :alt: 3-D display for spiny active neuron
+
+   3-D display for spiny active neuron
+
+Put a spine on a cylindrical compartment, give it synaptic input, and watch Ca diffuse.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Calcium enters spines during strong synaptic input, how far does it
+spread along the dendrites? This model is simple conceptually but
+illustrates several things:
+
+-  Setting up random (Poisson) synaptic input to one or more spines
+-  Setting up a reaction-diffusion system (Ca) coupled to an electrical
+   system (Ca influx through channels). This uses a separate chemical
+   definition script. One can replace this with more elaborate chemical
+   schemes simply by changing the name of the script.
+-  User definitions of prototypes (the soma in this example).
+-  Assigning random number seeds.
+-  The difference between electrical and chemical length scales. For
+   numerical reasons, the discretization of reaction-diffusion systems
+   into voxels normally happens on a smaller length scale (microns) than
+   for electrical systems (tens to hundreds of microns). In this example
+   there is just one electrical compartment, but 50 chemical
+   subdivisions.
+
+Most of the script is setting up the input and the prototypes.
+Rdesigneur is compact, as usual. First, the headers and parameter list:
+
+::
+
+    import moose
+    import numpy as np
+    import rdesigneur as rd
+
+    params = { 
+        'diffusionLength':1.0e-6,  # Diffusion characteristic length, used as voxel length too.
+        'dendDiameter': 1e-6,  # Diameter of section of dendrite in model
+        'dendLength': 50e-6,   # Length of section of dendrite in model
+        'spineSpacing': 30e-6,   # mean spacing between spines.
+        'diffConstCa':20.0e-12,  # Diffusion constant of Ca, m^2/sec
+        'spineFreq': 1,  # Frequencey of input to spines
+        'gluWeight': 100,  # Weight for glutamate receptor
+        'nmdaWeight': 100, # weight for NMDA receptor
+        'chemModel':'spineCa_diffn.g',  # Chem model definition.
+        'RA': 1.0,        # Axial resistivity of compartment, ohms.metre
+        'RM': 1.0,        # membrane resistivity of compartment, ohms.metre^2
+        'CM': 0.01,       # Specific capacitance of membrane, Farads/metre^2
+        'runtime': 3,      # Simulation run time, sec.
+    }
+
+Then, we define the prototypes for the soma compartment and the CaConc
+object that handles conversion of calcium current into calcium
+concentration:
+
+::
+
+    def makePassiveSoma( name, length, diameter ):
+        elecid = moose.Neuron( '/library/' + name )
+        dend = moose.Compartment( elecid.path + '/soma' )
+        dend.diameter = diameter
+        dend.length = length
+        dend.Ra = params['RA'] * length * 4.0 / (diameter * diameter * np.pi)
+        dend.Rm = params['RM'] / (length * diameter * np.pi)
+        dend.Cm = params['CM'] * length * diameter * np.pi
+        dend.x = length
+        return elecid
+
+    def makeCaConc( name ):
+        conc = moose.CaConc( '/library/' + name )
+        conc.tau = 0.0133333
+        conc.B = 17.402e12 # Conversion from Amps to milliMolar for soma
+        conc.Ca_base = 0.0 
+
+Then, we define the stimulus including the poisson spike generator:
+
+::
+
+    def attachStimulus():
+        numSpine = len( moose.wildcardFind( '/model/elec/head#' ) ) 
+        spikeInput = moose.RandSpike( '/model/elec/spineInput', numSpine )
+        spikeVec = spikeInput.vec
+        spikeVec.rate = params['spineFreq']
+
+        j = 0 
+        for i in moose.wildcardFind( '/model/elec/head#' ):
+            sh = moose.element( i.path + '/glu/sh' )
+            sh.numSynapses = 1 
+            sh.synapse[0].weight = params['gluWeight']
+            moose.connect( spikeVec[j], 'spikeOut', sh.synapse[0], 'addSpike')
+            sh = moose.element( i.path + '/NMDA/sh' )
+            sh.numSynapses = 1 
+            sh.synapse[0].weight = params['nmdaWeight']
+            moose.connect( spikeVec[j], 'spikeOut', sh.synapse[0], 'addSpike')
+            j += 1
+
+Having specified the framework for the model, here is the actual
+rdesigneur setup:
+
+::
+
+    moose.seed( 123 ) # One seed for the layout
+    library = moose.Neutral( '/library' )
+    makePassiveSoma( 'cell', params['dendLength'], params['dendDiameter'] )
+    makeCaConc( 'Ca_conc' )
+
+    rdes = rd.rdesigneur(
+        chemPlotDt = 0.02,
+        diffusionLength = params['diffusionLength'],
+        spineProto = [['makeExcSpine()', 'spine']],
+        spineDistrib = [['spine', '#', str( params['spineSpacing'] ),'1e-7']],
+        chanDistrib = [["Ca_conc", "#", "tau", "0.0133", "thick","0.1e-6"]],
+        cellProto = [['cell', 'elec']],
+        chemProto = [['../chem/' + params['chemModel'], 'chem']],
+        chemDistrib = [['chem', '#soma#', 'install', '1' ]],
+        plotList = [
+            ['soma', '1', '.', 'Vm', 'soma Vm'],
+            ['soma', '1', 'dend/DEND/Ca', 'conc', '[dend Ca]'],
+            ['#head#', '1', 'spine/Ca', 'conc', '[Spine Ca]'],
+            ['#head#', '1', 'psd/Ca', 'conc', '[PSD Ca]'],
+        ],
+        moogList = [['#', '1', 'dend/DEND/Ca', 'conc', 'dend Ca', 0, 0.5]],
+        adaptorList = [
+            [ 'Ca_conc', 'Ca', 'psd/Ca_input', 'concInit', 2e-6, 0.1 ],
+            [ 'Ca_conc', 'Ca','dend/DEND/Ca_input','concInit',2e-6,0.001],
+        ]
+    )
+    for ca in moose.wildcardFind( '/library/##/Ca' ):
+        ca.diffConst = params['diffConstCa']
+    rdes.buildModel()
+    attachStimulus()
+    moose.reinit()
+    moose.seed( 3 ) # Another seed because the reinit does a reseed.
+    rdes.displayMoogli( 0.01, params['runtime'], 0.0 )
+
+You will additionally need to copy over the chemical models for the
+calcium. These reside in the moose-examples/genesis directory. The
+simple model ``spineCa_diffn.g`` has calcium in spine PSD, spine head,
+and dendrite pools, with reactions for controlling input from the
+*Ca\_conc* object.
+
+With this done you can run the script and watch calcium spreading from
+the location of the spine. There are three pulses of calcium, the first
+being quite weak.
+
+.. figure:: ../../../../images/rdes10_CaSpread.png
+   :alt: Calcium influx from spine in middle of cylindrical compartment,
+   spreading into the dendrite and then axially in both directions.
+
+   Calcium influx from spine in middle of cylindrical compartment,
+   spreading into the dendrite and then axially in both directions.
+
+Once the simulation completes you'll also see a number of plots, so that
+you can figure out what the calcium influx was doing. Here, we have a
+single spine so there is just one trace for it. We have 50 chemical
+voxels along the dendrite, so there are 50 traces for the chemical
+time-course.
+
+.. figure:: ../../../../images/rdes10_CaTimecourse.png
+   :alt: Time-course of Calcium buildup in spine and dendrite.
+
+   Time-course of Calcium buildup in spine and dendrite.
+
+Note the explicit assignment of random seeds using
+``moose.seed( 123 )``. By default, MOOSE generates a reasonably random
+seed using system information. Here, however, we want to be sure that
+the simulation always gives the same result. So we explicitly set the
+seed to a known number. Note also that we set the seed at two places:
+First, before setup, so that we ensure that the spines are going to come
+in the same number and place each time. Second, after ``moose.reinit()``
+to make sure that the same pseudo-random sequence of synaptic input and
+chemical stochastic calculations happens each run.
+
+Note also that this is run using stochastic methods for the chemical
+calculations. This is the default. One can alter this using the
+following line in rdesigneur:
+
+::
+
+        useGssa = False
+
+As an exercise for the user, we also have a plug-in replaceable model
+for Ca influx, this one having a lot of calmodulin to act as a buffer.
+Replace the original line in the params dictionary as follows:
+
+::
+
+        'chemModel':'spineCa_diffn.g'
+
+with
+
+::
+
+        'chemModel':'spineCa_CaM_diffn.g'
+
+The resultant model has reduced free Ca++ buildup.
+
+Some other interesting things to try are:
+
+-  Increase the diffusion constant for calcium. You might expect that
+   this would lead to faster flow of Ca from the spine to the dendrite,
+   and hence a higher peak in the dendrite. Try it and see.
+-  Change the diameter of the dendrite.
+
+.. Build a spiny neuron from a morphology file and put a reaction-diffusion system in it.
+.. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. Rdesigneur is specially designed to take reaction systems with a
+   dendrite, a spine head, and a spine PSD compartment, and embed these
+   systems into neuronal morphologies. This example shows how this is done.
+
+   The dendritic molecules diffuse along the dendrite in the region
+   specified by the *chemDistrib* keyword. In this case they are placed on
+    all apical and basal dendrites, but only at distances over 500 microns
+   from the soma. The spine head and PSD reaction systems are inserted only
+   into spines within this same *chemDistrib* zone. Diffusion coupling
+   between dendrite, and each spine head and PSD is also set up. It takes a
+   predefined chemical model file for Rdesigneur, which resides in the
+   ``./chem`` subdirectory. As in an earlier example, we turn off the
+   electrical calculations here as they are not needed. Here we plot out
+   the number of receptors on every single spine as a function of time.
+
+   (Documentation still to come here)
+
+.. Make a full multiscale model with complex spiny morphology and electrical and chemical signaling.
+.. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. (Documentation still to come here)
diff --git a/docs/source/user/py/cookbook/multi_rdes.rst b/docs/source/user/py/cookbook/multi_rdes.rst
index dce3f358..baf5719b 100644
--- a/docs/source/user/py/cookbook/multi_rdes.rst
+++ b/docs/source/user/py/cookbook/multi_rdes.rst
@@ -1,6 +1,6 @@
-**********
-RDesigneur
-**********
+************************
+More Rdesigneur Examples
+************************
 
 Building Chemical-Electrical Signalling Models
 ----------------------------------------------
diff --git a/docs/source/user/py/cookbook/multiscale.rst b/docs/source/user/py/cookbook/multiscale.rst
index a8a83165..d751d3e4 100644
--- a/docs/source/user/py/cookbook/multiscale.rst
+++ b/docs/source/user/py/cookbook/multiscale.rst
@@ -6,4 +6,8 @@ MultiScale Modeling
    :maxdepth: 2
 
    multi_sim_eg
+   Rd
    multi_rdes
+   
+
+
-- 
GitLab