コード例 #1
0
ファイル: DistalSynapse.cs プロジェクト: intruder01/20150105
 /// <summary>
 /// Add new DataTable to existing DataSet
 /// </summary>
 /// <param name="dataSet"></param>
 public new void AddWatchTable(ref DataSet dataSet, string tableName = "")
 {
     dataSet.Tables.Add(this.DataTable(tableName));
     dataSet.Tables.Add(DistalSegment.DataTable(tableName));                //not sure if necc
     dataSet.Tables.Add(InputSource.DataTable(tableName));                  //not sure if necc
     base.AddWatchTable(ref dataSet, tableName);
 }
コード例 #2
0
ファイル: SegmentUpdate.cs プロジェクト: intruder01/20150105
        ///<summary>
        /// Create a new segment on the update cell using connections from
        /// the set of learning cells for the update info.
        ///</summary>
        internal DistalSegment CreateDistalSegment()
        {
            DistalSegment distalSegment = this.Cell.CreateDistalSegment(this.CellsToConnect);

            distalSegment.NumberPredictionSteps = this.NumberPredictionSteps;
            return(distalSegment);
        }
コード例 #3
0
ファイル: Cell.cs プロジェクト: intruder01/20150105
        /// <summary>
        /// For this cell, return a <see cref="Segment"/> that is active in the given
        /// time step. If multiple segments are active, sequence segments are given
        /// preference. Otherwise, segments with most activity are given preference.
        /// Original name: getActiveSegment
        /// </summary>
        public DistalSegment GetActiveDistalSegment(int t)
        {
            DistalSegment bestDistalSegment        = null;
            bool          foundSequenceSegment     = false;
            int           bestNumberActiveSynapses = 0;

            foreach (var segment in this.DistalSegments)
            {
                int numberActiveSynapses = segment.GetActiveSynapses(t).Count;

                if (numberActiveSynapses >= Segment.ActivationThreshold)
                {
                    // Sequence segments are given preference.
                    // Otherwise, segments with most activity are given preference.
                    if (segment.IsSequence)
                    {
                        foundSequenceSegment = true;
                        if (numberActiveSynapses > bestNumberActiveSynapses)
                        {
                            bestNumberActiveSynapses = numberActiveSynapses;
                            bestDistalSegment        = segment;
                        }
                    }
                    else if (!foundSequenceSegment && numberActiveSynapses > bestNumberActiveSynapses)
                    {
                        bestNumberActiveSynapses = numberActiveSynapses;
                        bestDistalSegment        = segment;
                    }
                }
            }

            return(bestDistalSegment);
        }
コード例 #4
0
ファイル: DistalSynapse.cs プロジェクト: intruder01/20150105
        /// <summary>
        /// Object's identification string based on it's position within parent.
        /// Used primarly in Watch.
        /// </summary>
        /// <returns></returns>
        public new string ID()
        {
            string str = "";

            //str = String.Format ( "Synapse [" + Parent.ID () + "]" );
            str = String.Format("DistalSynapse[{0}]", DistalSegment.ID());
            return(str);
        }
コード例 #5
0
ファイル: Column.cs プロジェクト: intruder01/20150105
        /// <summary>
        /// For this column, return the cell with the best matching <see cref="Segment"/>
        /// (at time t-1 or t). Only consider segments that are predicting cell activation
        /// to occur in exactly numberPredictionSteps many time steps from now. If no cell
        /// has a matching segment, then return the cell with the fewest number of segments.
        /// </summary>
        /// <param name="t">only consider active segments at time t.</param>
        /// <param name="numberPredictionSteps">only consider segments that are predicting
        /// cell activation to occur in exactly this many time steps from now.</param>
        /// <returns>Tuple containing the best cell and its best <see cref="Segment"/>
        /// (may be None).</returns>
        internal Tuple <Cell, DistalSegment> GetBestMatchingCell(int t, int numberPredictionSteps)
        {
            Cell          bestCell                 = null;
            DistalSegment bestDistalSegment        = null;
            int           bestNumberActiveSynapses = 0;

            // Chooses the cell with the best matching segment.
            foreach (var cell in this.Cells)
            {
                DistalSegment distalSegment = cell.GetBestMatchingDistalSegment(t, numberPredictionSteps);

                if (distalSegment != null)
                {
                    int numberActiveSynapses = distalSegment.GetActiveSynapses(t).Count;
                    if (numberActiveSynapses > bestNumberActiveSynapses)
                    {
                        bestCell                 = cell;
                        bestDistalSegment        = distalSegment;
                        bestNumberActiveSynapses = numberActiveSynapses;
                    }
                }
            }

            // If there are no active sequences, return the cell with the fewest number of
            // segments
            if (bestCell == null)
            {
                int bestNumberActiveSegments = int.MaxValue;
                foreach (var cell in this.Cells)
                {
                    int numberActiveSegments = cell.DistalSegments.Count;
                    if (numberActiveSegments < bestNumberActiveSegments)
                    {
                        bestNumberActiveSegments = numberActiveSegments;
                        bestCell = cell;
                    }
                }

                // Pick a random cell among those with equal segment counts
                // TODO: is there a more efficient way to do this maybe?
                var candidates = new List <Cell>();
                foreach (var cell in this.Cells)
                {
                    if (cell.DistalSegments.Count == bestNumberActiveSegments)
                    {
                        candidates.Add(cell);
                    }
                }
                if (candidates.Count > 1)
                {
                    bestCell = candidates[this._random.Next(candidates.Count)];
                }

                // Leave bestSegment null to indicate a new segment is to be added
            }

            return(new Tuple <Cell, DistalSegment>(bestCell, bestDistalSegment));
        }
コード例 #6
0
ファイル: Cell.cs プロジェクト: intruder01/20150105
        /// <summary>
        /// Creates a new distal segment for this Cell.
        /// </summary>
        /// <param name="cellsToConnect"> A set of available cells to add to
        /// the segmentUpdateList.</param>
        /// <returns> Created segmentUpdateList</returns>
        /// <remarks>
        /// The new segment will initially connect to at most newNumberSynapses
        /// synapses randomly selected from the set of cells that
        /// were in the learning state at t-1 (specified by the learningCells parameter).
        /// </remarks>
        internal DistalSegment CreateDistalSegment(List <Cell> cellsToConnect)
        {
            var newDistalSegment = new DistalSegment(this);

            foreach (var cell in cellsToConnect)
            {
                newDistalSegment.CreateSynapse(cell, Synapse.InitialPermanence);
            }

            this.DistalSegments.Add(newDistalSegment);
            return(newDistalSegment);
        }
コード例 #7
0
ファイル: Cell.cs プロジェクト: intruder01/20150105
        ///<summary>
        /// Add a new <see cref="SegmentUpdate"/> object to this <see cref="Cell"/>
        /// containing proposed changes to the specified segment.
        ///</summary>
        ///<remarks>
        /// If the segment is None, then a new segment is to be added, otherwise
        /// the specified segment is updated.  If the segment exists, find all active
        /// synapses for the segment (either at t or t-1)
        /// and mark them as needing to be updated.  If newSynapses is true, then
        /// Region.newNumberSynapses - len(activeSynapses) new synapses are added to the
        /// segment to be updated.  The (new) synapses are randomly chosen from the set
        /// of current learning cells (within Region.localityRadius if set).
        ///
        /// These segment updates are only applied when the applySegmentUpdates
        /// method is later called on this Cell.
        ///</remarks>
        internal SegmentUpdate UpdateDistalSegmentActiveSynapses(int t, DistalSegment distalSegment, bool newSynapses = false)
        {
            // Let ActiveSynapses be the list of active synapses where the originating
            // cells have their ActiveState output = true at time step t.
            // (This list is empty if segment = null since the segment doesn't exist.)
            var activeSynapses = new List <Synapse>();

            if (distalSegment != null)
            {
                activeSynapses = distalSegment.GetActiveSynapses(t);
            }

            var segmentUpdate = new SegmentUpdate(this, distalSegment, activeSynapses, newSynapses);

            this.SegmentUpdates.Add(segmentUpdate);

            return(segmentUpdate);
        }
コード例 #8
0
ファイル: Cell.cs プロジェクト: intruder01/20150105
        ///<summary>
        /// This function reinforces each segment in this Cell's SegmentUpdate.
        /// </summary>
        /// <remarks>
        /// Using the segmentUpdate, the following changes are
        /// performed. If positiveReinforcement is true then synapses on the active
        /// list get their permanence counts incremented by permanenceInc. All other
        /// synapses get their permanence counts decremented by permanenceDec. If
        /// positiveReinforcement is false, then synapses on the active list get
        /// their permanence counts decremented by permanenceDec. After this step,
        /// any synapses in segmentUpdate that do yet exist get added with a permanence
        /// count of initialPerm. These new synapses are randomly chosen from the
        /// set of all cells that have learnState output = 1 at time step t.
        ///</remarks>
        internal void ApplySegmentUpdates(bool positiveReinforcement, int latestCreationStep = -1)
        {
            // This loop iterates through a list of SegmentUpdate's and reinforces each segment.
            foreach (var segmentUpdate in this.SegmentUpdates)
            {
                DistalSegment distalSegment = segmentUpdate.DistalSegment;

                if (distalSegment != null)
                {
                    if (positiveReinforcement)
                    {
                        distalSegment.UpdatePermanences(segmentUpdate.ActiveDistalSynapses);
                    }
                    else
                    {
                        distalSegment.DecreasePermanences(segmentUpdate.ActiveDistalSynapses);
                    }
                }

                // Add new synapses (and new segment if necessary)
                if (segmentUpdate.AddNewSynapses && positiveReinforcement)
                {
                    if (distalSegment == null)
                    {
                        // Only add new segment if end cells to connect are available
                        if (segmentUpdate.CellsToConnect.Count > 0)
                        {
                            distalSegment = segmentUpdate.CreateDistalSegment();
                        }
                    }
                    else if (segmentUpdate.CellsToConnect.Count > 0)
                    {
                        // Add new synapses to existing segment
                        segmentUpdate.CreateDistalSynapses();
                    }
                }
            }

            // Delete segment update instances after they are applied
            this.SegmentUpdates.Clear();
        }
コード例 #9
0
ファイル: Cell.cs プロジェクト: intruder01/20150105
        /// <summary>
        /// Gets the best matching <see cref="Segment"/>.
        /// </summary>
        /// <param name="t">Only consider active segments at time t.</param>
        /// <param name="numberPredictionSteps">Number of time steps in the future an activation will occur.</param>
        /// <remarks>
        /// For this cell (at t or t-1), find the <see cref="Segment"/> (only
        /// consider sequence segments if isSequence is True, otherwise only consider
        /// non-sequence segments) with the largest number of active synapses.
        /// This routine is aggressive in finding the best match. The permanence
        /// value of synapses is allowed to be below connectedPerm.
        /// The number of active synapses is allowed to be below activationThreshold,
        /// but must be above minThreshold. The routine returns that segment.
        /// If no segments are found, then null is returned.
        /// </remarks>
        internal DistalSegment GetBestMatchingDistalSegment(int t, int numberPredictionSteps)
        {
            DistalSegment bestDistalSegment        = null;
            int           bestNumberActiveSynapses = _minSynapsesPerSegmentThreshold;

            foreach (var segment in this.DistalSegments)
            {
                if (segment.NumberPredictionSteps == numberPredictionSteps)
                {
                    // Get all the active synapses in the given t time step, no matter connection value
                    int numberActiveSynapses = segment.GetActiveSynapses(t).Count;
                    if (numberActiveSynapses >= bestNumberActiveSynapses)
                    {
                        bestNumberActiveSynapses = numberActiveSynapses;
                        bestDistalSegment        = segment;
                    }
                }
            }

            return(bestDistalSegment);
        }
コード例 #10
0
ファイル: Cell.cs プロジェクト: intruder01/20150105
        /// <summary>
        /// Gets the sequence segment. If it's not null then this cell was predicted to
        /// become active at current time step.
        /// </summary>
        /// <value>The segment predicting or null if none found.</value>
        public DistalSegment GetSequencePredictingDistalSegment()
        {
            DistalSegment predictingDistalSegment = null;

            try
            {
                if (this.PredictiveState[Global.T - 1])
                {
                    DistalSegment distalSegment = this.GetActiveDistalSegment(Global.T - 1);
                    if (distalSegment != null && distalSegment.IsSequence)
                    {
                        predictingDistalSegment = distalSegment;
                    }
                }
            }
            catch (InvalidOperationException)
            {
            }

            return(predictingDistalSegment);
        }
コード例 #11
0
ファイル: DistalSynapse.cs プロジェクト: intruder01/20150105
 /// <summary>
 /// Initializes a new instance of the <see cref="DistalSynapse"/> class and
 /// sets its input source and initial permanance values.
 /// </summary>
 /// <param name="distalSeg">
 /// </param>
 /// <param name="inputSource">
 /// An object providing source of the input to this synapse (either
 /// a <see cref="Column"/>'s <see cref="Cell"/> or a special
 /// <see cref="InputCell"/>).
 /// </param>
 /// <param name="permanence">Initial permanence value.</param>
 public DistalSynapse(DistalSegment distalSeg, Cell inputSource, float permanence)
     : this(inputSource, permanence)
 {
     // Set fields
     this.DistalSegment = distalSeg;
 }
コード例 #12
0
ファイル: DistalSynapse.cs プロジェクト: intruder01/20150105
 /// <summary>
 /// Initializes a new instance of the <see cref="DistalSynapse"/> class and 
 /// sets its input source and initial permanance values.
 /// </summary>
 /// <param name="distalSeg">
 /// </param>
 /// <param name="inputSource">
 /// An object providing source of the input to this synapse (either 
 /// a <see cref="Column"/>'s <see cref="Cell"/> or a special 
 /// <see cref="InputCell"/>).
 /// </param>
 /// <param name="permanence">Initial permanence value.</param>
 public DistalSynapse(DistalSegment distalSeg, Cell inputSource, float permanence)
     : this(inputSource, permanence)
 {
     // Set fields
     this.DistalSegment = distalSeg;
 }
コード例 #13
0
ファイル: SegmentUpdate.cs プロジェクト: intruder01/20150105
        ///<summary>
        ///Create a new SegmentUpdate that is to modify the state of the Region
        ///either by adding a new segment to a cell, new synapses to a segemnt,
        ///or updating permanences of existing synapses on some segment.
        ///</summary>
        ///<param name="cell">cell the cell that is to have a segment added or updated.
        ///  </param>
        ///<param name="distalSegment">the segment that is to be updated (null here means a new
        ///  segment is to be created on the parent cell).</param> 
        ///<param name="activeDistalSynapses">the set of active synapses on the segment 
        ///  that are to have their permanences updated.</param> 
        ///<param name="addNewSynapses">set to true if new synapses are to be added to the
        ///  segment (or if new segment is being created) or false if no new synapses
        ///  should be added instead only existing permanences updated.</param> 
        ///
        public SegmentUpdate(Cell cell, DistalSegment distalSegment, List<Synapse> activeDistalSynapses,
		                     bool addNewSynapses = false)
        {
            // Set fields
            this.Cell = cell;
            this.DistalSegment = distalSegment;
            this.ActiveDistalSynapses = new List<Synapse>(activeDistalSynapses);
            this.AddNewSynapses = addNewSynapses;
            this.CellsToConnect = new List<Cell>();
            this.NumberPredictionSteps = 1;
            this.CreationStep = (int) cell.Statistics.StepCounter;

            // Set of cells that have LearnState output = true at time step t.
            var cellsToConnect = new List<Cell>();

            // If adding new synapses, find the current set of learning cells within
            // the Region and select a random subset of them to connect the segment to.
            // Do not add > 1 synapse to the same cell on a given segment
            Region region = this.Cell.Column.Region;

            if (this.AddNewSynapses)
            {
                // Gather all cells from segment in order to avoid use them as learning cells.
                var cellsInSegment = new List<Cell>();
                if (distalSegment != null)
                {
                    foreach (var synapse in distalSegment.Synapses)
                    {
                        if (synapse is DistalSynapse)
                        {
                            cellsInSegment.Add(((DistalSynapse) synapse).InputSource);
                        }
                    }
                }

                // Define limits to choose cells to connect.
                int minY, maxY, minX, maxX;
                if (region.LocalityRadius > 0)
                {
                    // Only allow connecting to Columns within locality radius
                    minX = Math.Max(0, cell.Column.PositionInRegion.X - region.LocalityRadius);
                    minY = Math.Max(0, cell.Column.PositionInRegion.Y - region.LocalityRadius);
                    maxX = Math.Min(region.Size.Width - 1,
                                    cell.Column.PositionInRegion.X + region.LocalityRadius);
                    maxY = Math.Min(region.Size.Height - 1,
                                    cell.Column.PositionInRegion.Y + region.LocalityRadius);
                }
                else
                {
                    // Now I want to allow connections over all the region!
                    // If locality radius is 0, it means 'no restriction'
                    minX = 0;
                    minY = 0;
                    maxX = region.Size.Width - 1;
                    maxY = region.Size.Height - 1;
                }

                // Set of cells that have LearnState output = true at time step t.
                for (int x = minX; x <= maxX; x++)
                {
                    for (int y = minY; y <= maxY; y++)
                    {
                        Column column = region.GetColumn(x, y);

                        // Skip cells in our own column (don't connect to ourself)
                        if (column != cell.Column)
                        {
                            foreach (var learningCell in column.Cells)
                            {
                                // Skip cells that already are linked to the segment (case it exists).
                                if (learningCell.LearnState[Global.T - 1] && !cellsInSegment.Contains(learningCell))
                                {
                                    cellsToConnect.Add(learningCell);
                                }
                            }
                        }
                    }
                }
            }

            // Basic allowed number of new Synapses
            int newNumberSynapses = region.NumberNewSynapses;
            if (distalSegment != null)
            {
                newNumberSynapses = Math.Max(0, newNumberSynapses - activeDistalSynapses.Count);
            }

            // Clamp at learn cells
            newNumberSynapses = Math.Min(cellsToConnect.Count, newNumberSynapses);

            // Randomly choose (newNumberSynapses) learning cells to add connections to
            if (cellsToConnect.Count > 0 && newNumberSynapses > 0)
            {
                this.CellsToConnect = this.ChooseRandomCells(cellsToConnect, newNumberSynapses);
            }
        }
コード例 #14
0
ファイル: SegmentUpdate.cs プロジェクト: intruder01/20150105
        ///<summary>
        ///Create a new SegmentUpdate that is to modify the state of the Region
        ///either by adding a new segment to a cell, new synapses to a segemnt,
        ///or updating permanences of existing synapses on some segment.
        ///</summary>
        ///<param name="cell">cell the cell that is to have a segment added or updated.
        ///  </param>
        ///<param name="distalSegment">the segment that is to be updated (null here means a new
        ///  segment is to be created on the parent cell).</param>
        ///<param name="activeDistalSynapses">the set of active synapses on the segment
        ///  that are to have their permanences updated.</param>
        ///<param name="addNewSynapses">set to true if new synapses are to be added to the
        ///  segment (or if new segment is being created) or false if no new synapses
        ///  should be added instead only existing permanences updated.</param>
        ///
        public SegmentUpdate(Cell cell, DistalSegment distalSegment, List <Synapse> activeDistalSynapses,
                             bool addNewSynapses = false)
        {
            // Set fields
            this.Cell                  = cell;
            this.DistalSegment         = distalSegment;
            this.ActiveDistalSynapses  = new List <Synapse>(activeDistalSynapses);
            this.AddNewSynapses        = addNewSynapses;
            this.CellsToConnect        = new List <Cell>();
            this.NumberPredictionSteps = 1;
            this.CreationStep          = (int)cell.Statistics.StepCounter;

            // Set of cells that have LearnState output = true at time step t.
            var cellsToConnect = new List <Cell>();

            // If adding new synapses, find the current set of learning cells within
            // the Region and select a random subset of them to connect the segment to.
            // Do not add > 1 synapse to the same cell on a given segment
            Region region = this.Cell.Column.Region;

            if (this.AddNewSynapses)
            {
                // Gather all cells from segment in order to avoid use them as learning cells.
                var cellsInSegment = new List <Cell>();
                if (distalSegment != null)
                {
                    foreach (var synapse in distalSegment.Synapses)
                    {
                        if (synapse is DistalSynapse)
                        {
                            cellsInSegment.Add(((DistalSynapse)synapse).InputSource);
                        }
                    }
                }

                // Define limits to choose cells to connect.
                int minY, maxY, minX, maxX;
                if (region.LocalityRadius > 0)
                {
                    // Only allow connecting to Columns within locality radius
                    minX = Math.Max(0, cell.Column.PositionInRegion.X - region.LocalityRadius);
                    minY = Math.Max(0, cell.Column.PositionInRegion.Y - region.LocalityRadius);
                    maxX = Math.Min(region.Size.Width - 1,
                                    cell.Column.PositionInRegion.X + region.LocalityRadius);
                    maxY = Math.Min(region.Size.Height - 1,
                                    cell.Column.PositionInRegion.Y + region.LocalityRadius);
                }
                else
                {
                    // Now I want to allow connections over all the region!
                    // If locality radius is 0, it means 'no restriction'
                    minX = 0;
                    minY = 0;
                    maxX = region.Size.Width - 1;
                    maxY = region.Size.Height - 1;
                }

                // Set of cells that have LearnState output = true at time step t.
                for (int x = minX; x <= maxX; x++)
                {
                    for (int y = minY; y <= maxY; y++)
                    {
                        Column column = region.GetColumn(x, y);

                        // Skip cells in our own column (don't connect to ourself)
                        if (column != cell.Column)
                        {
                            foreach (var learningCell in column.Cells)
                            {
                                // Skip cells that already are linked to the segment (case it exists).
                                if (learningCell.LearnState[Global.T - 1] && !cellsInSegment.Contains(learningCell))
                                {
                                    cellsToConnect.Add(learningCell);
                                }
                            }
                        }
                    }
                }
            }

            // Basic allowed number of new Synapses
            int newNumberSynapses = region.NumberNewSynapses;

            if (distalSegment != null)
            {
                newNumberSynapses = Math.Max(0, newNumberSynapses - activeDistalSynapses.Count);
            }

            // Clamp at learn cells
            newNumberSynapses = Math.Min(cellsToConnect.Count, newNumberSynapses);

            // Randomly choose (newNumberSynapses) learning cells to add connections to
            if (cellsToConnect.Count > 0 && newNumberSynapses > 0)
            {
                this.CellsToConnect = this.ChooseRandomCells(cellsToConnect, newNumberSynapses);
            }
        }
コード例 #15
0
ファイル: Cell.cs プロジェクト: intruder01/20150105
        ///<summary>
        /// Add a new <see cref="SegmentUpdate"/> object to this <see cref="Cell"/>
        /// containing proposed changes to the specified segment. 
        ///</summary>
        ///<remarks>
        /// If the segment is None, then a new segment is to be added, otherwise
        /// the specified segment is updated.  If the segment exists, find all active
        /// synapses for the segment (either at t or t-1)
        /// and mark them as needing to be updated.  If newSynapses is true, then
        /// Region.newNumberSynapses - len(activeSynapses) new synapses are added to the
        /// segment to be updated.  The (new) synapses are randomly chosen from the set
        /// of current learning cells (within Region.localityRadius if set).
        ///
        /// These segment updates are only applied when the applySegmentUpdates
        /// method is later called on this Cell.
        ///</remarks>
        internal SegmentUpdate UpdateDistalSegmentActiveSynapses(int t, DistalSegment distalSegment, bool newSynapses = false)
        {
            // Let ActiveSynapses be the list of active synapses where the originating
            // cells have their ActiveState output = true at time step t.
            // (This list is empty if segment = null since the segment doesn't exist.)
            var activeSynapses = new List<Synapse>();
            if (distalSegment != null)
            {
                activeSynapses = distalSegment.GetActiveSynapses(t);
            }

            var segmentUpdate = new SegmentUpdate(this, distalSegment, activeSynapses, newSynapses);
            this.SegmentUpdates.Add(segmentUpdate);

            return segmentUpdate;
        }
コード例 #16
0
ファイル: Cell.cs プロジェクト: intruder01/20150105
        /// <summary>
        /// Creates a new distal segment for this Cell.
        /// </summary>
        /// <param name="cellsToConnect"> A set of available cells to add to 
        /// the segmentUpdateList.</param>
        /// <returns> Created segmentUpdateList</returns>
        /// <remarks>
        /// The new segment will initially connect to at most newNumberSynapses 
        /// synapses randomly selected from the set of cells that
        /// were in the learning state at t-1 (specified by the learningCells parameter).
        /// </remarks>
        internal DistalSegment CreateDistalSegment(List<Cell> cellsToConnect)
        {
            var newDistalSegment = new DistalSegment( this );

            foreach (var cell in cellsToConnect)
            {
                newDistalSegment.CreateSynapse(cell, Synapse.InitialPermanence);
            }

            this.DistalSegments.Add(newDistalSegment);
            return newDistalSegment;
        }