AnyLogic
Expand
Font size

Storage

Storage in 2DStorage in graphical editor Storage in 3DStorage at model runtime in 3D animation

Storage is a space markup element that you can use to graphically define a warehouse space where agents (material items) are stored on racks.

One storage element can contain multiple racks. At the moment we support the following rack placement:

  • Stand-alone — all racks face in the same direction and each aisle can provide access to a single rack.

    Stand-alone rack placementStand-alone placement

  • Back-to-back — the racks are organized in pairs back-to-back. This way each aisle provides access to two racks.

    Back-to-back rack placementBack-to-back placement

Each rack is composed of cells. A single cell can host a single agent (material item). Inside the rack, cells are organized in specific groups that are used to define how the rack is filled. Let's take a closer look:

In the images below you will see a single rack that consists of 2 bays and 5 shelves, where each shelf is 5 cells deep.
Rack with one slot filled Slot — a single horizontal row of cells that defines the depth of a rack. By default, each rack in the Storage has one cell per slot.
Rack with one bay filled Bay — a number of slots stacked vertically on top of each other. The width of a rack depends on the number of bays. By default, each rack in the Storage has five bays.
Rack with one shelf filled Shelf — a number of slots arranged horizontally at the same height. The height of a rack depends on the number of shelves. By default, each rack in the Storage has one shelf.

Currently, Storage element supports the racks of the following types:

  • Selective — The rack is filled bay by bay. In each bay, the slot on the bottom is filled completely starting with the deepest cell position, then the slot above it is filled in the same manner. The process repeats until the bay is filled from the bottom shelf all the way to the top shelf. This type supports LIFO flow: the last stored item will be the first item to retrieve.
  • Drive-in — The deepest cell positions in all available slots on the bottom are filled first. Then the cells directly above them, and so on, until all cells in the deepest positions are filled in the rack. Next, the process repeats for the cells that are now considered to be in the deepest positions. This rack type supports LIFO flow: the last stored item will be the first item to retrieve.

Storages can serve as obstacles on the way of pedestrians and transporters moving in free space navigation mode.

Creating a storage

There are two approaches to creating a storage: either based on the dimensions of the storage units (racks and bays) or based on the explicitly defined number of racks and bays.

To draw a storage based on dimensions

  1. Drag the Storage element from the Space Markup palette into the graphical editor.
  2. Specify the dimensions of the storage units according to your needs:
    • Set the Number of racks and the Number of bays to be calculated based on dimensions.
    • Specify the storage's Rack depth, Aisle width, and Bay width.
    • Set the Number of cells per slot.
    • Define the Number of shelves and Shelf height.
  3. After you have configured the dimensions, drag the handle in the bottom right corner of the Storage element and resize it to fit your demands. The number of racks and bays will automatically increase/decrease according to the size of the whole storage.

    Drawing a storage based on dimensions

  4. In the Appearance section of the properties you can customize the look of your storage. You can also choose how the agents (material items) inside the storage are animated at runtime by setting the Occupied cells animation property. If you choose color indication (fast) option, the cells with material items will be simply colored at runtime. Use this option if you model extensive storage areas and need to improve model performance. If you don't have any issues with performance, you can use agent animation option: this way you will see the actual animation of the material items inside the storage.
  5. Define the width of the Access zone in the Position and size section of the storage properties. Access zone is the area located in front of the first rack in the storage. All network paths that go through the access zone can be used by transporters or resources to approach the rack.
  6. After you have finished drawing the storage, click Create storage network to draw network paths inside the storage aisles if you need those.

    Make sure that you have indeed finished drawing the storage, because once you draw the network, it will not adjust automatically to any further changes in the storage dimensions. You would have to delete the network altogether and create one from scratch.

To draw a storage based on the number of racks and bays

  1. Drag the Storage element from the Space Markup palette into the graphical editor.
  2. Specify the Number of racks and the Number of bays according to your needs.
  3. Set the Number of cells per slot.
  4. Define the Number of shelves and Shelf height.
  5. Drag the handle in the bottom right corner of the Storage element and resize it to fit your demands. The dimensions of bays and aisles will automatically change according to the size of the whole storage.

    Drawing a storage based on explicit numbers

  6. Adjust the rack depth if necessary.
  7. Adjust the aisle width if necessary.
  8. In the Appearance section of the properties you can customize the look of your storage. You can also choose how the agents (material items) inside the storage are animated at runtime by setting the Occupied cells animation property. If you choose color indication (fast) option, the cells with material items will be simply colored at runtime. Use this option if you model extensive storage areas and need to improve model performance. If you don't have any issues with performance, you can use agent animation option: this way you will see the actual animation of the material items inside the storage.
  9. Define the width of the Access zone in the Position and size section of the storage properties. Access zone is the area located in front of the first rack in the storage. All network paths that go through the access zone can be used by transporters or resources to approach the rack.
  10. After you have finished drawing the storage, click Create storage network to draw network paths inside the storage aisles if you need those.

    Make sure that you have indeed finished drawing the storage, because once you draw the network, it will not adjust automatically to any further changes in the storage dimensions. You would have to delete the network altogether and create one from scratch.

Cell

The coordinates of every cell in Storage can be described as a set of indices, where each index describes a specific rack, bay, shelf, and the cell's position in the slot. Let's use the getCell() function as an example.

Suppose, we have a Storage element named storage that consists of 4 racks, where each rack has 5 bays, 5 shelves, and 10-cell slots. We want to obtain the deepest cell from the highest shelf in the 3rd bay of the 4th rack. Since indices are calculated from 0, we have to call the storage.getCell(3, 2, 4, 9) function, where:

  • 3 — the index of the 4th rack
  • 2 — the index of the 3rd bay
  • 4 — the index of the highest (the 5th out of 5) shelf
  • 9 — the index of the deepest (the 10th out of 10) cell

Cells unavailable for storage

Inside the warehouses there may be some empty areas that interrupt the otherwise uniform flow of storage space. You can use specific functions and make whole groups of cells inaccessible for storage in order to model these areas.

Agents (material items) can still be transported through these areas.

There is an aisle in front of each rack in the storage. If you are using resources or transporters to move agents to / from the storage, transporters and resources will move through aisles to get as close as possible to the cell where they can drop off or pick up the agent. After configuring the storage to your satisfaction, you can create a storage network to be used by resources or transporters with path-guided navigation to move inside the storage. The paths of this network will go through the storage aisles.

Besides, every storage has an access zone that is located in front of the first rack of the storage. In case of back-to-back storage configuration, there are two access zones: in front of the first rack and in front of the last rack of the storage. All network paths that go through the access zone can be used by transporters or resources to approach the rack. You can adjust the width of the access zone as you see fit.

Alternatively, if you're modeling at a higher level of abstraction and want to skip the detailed process of storage and retrieval, the agents (material items) can arrive at the storage on their own.

Editing the Storage in graphical editor

Since the graphical representation of storage is pretty complex, here are some quick scenarios on how you can adjust the storage in design time.

To adjust the aisle width

  1. Drag the first square handle on the first rack of the storage to change the width of all aisles.

    Changing the aisle width in graphical editor

To adjust the rack depth

  1. Drag the second square handle on the first rack of the storage to change the depth of all racks.

    Changing the aisle width in graphical editor

To adjust the access zone

  1. Drag the diamond-shaped handle on the access zone border to adjust its width.

    Changing the width of the access zone

Properties

General

Name — The name of the rack storage. The name is used to identify and access the storage from code and library blocks.

Ignore — If selected, the storage is excluded from the model.

Visible on upper agent — If selected, the storage is also visible on the upper agent where this agent lives.

Lock — If selected, the shape of the storage is locked. Locked shapes do not react to mouse clicks — it is impossible to select them in the graphical editor until you unlock them. This may prove useful when you want to prevent editing this shape while drawing other shapes over it.

Visible — Here you specify whether the shape is visible on animation at model runtime, or not.

Is obstacle — If selected, this rack storage will be considered an obstacle for pedestrians and transporters moving in free space mode.

Rack type — The type of storage that defines how agents are stored inside the rack. The following options are available:

  • Selective — The rack is filled bay by bay from the bottom shelf up. This type supports LIFO SKU flow. The seized resource or transporter waits in the aisle while the item is stored.
  • Drive-in — The deepest positions in all available bays are filled first from the bottom shelf up. This type supports LIFO SKU flow. The seized transported or resource drives inside the bay to store the item.

Rack placement — Here you can choose how the racks are positioned inside the storage:

  • Back-to-back — racks are organized in pairs and stand back-to-back
  • Stand-alone — all racks face in the same direction

Rack depth — Here you can define the depth of a single rack.

Number of racks is — Here you can select how the number of racks in your storage is defined. It is either:

  • defined explicitly — you specify the Number of racks in the corresponding property below
  • calculated based on dimensions — you define the dimensions of the rack, aisle, and storage itself, and AnyLogic calculates the number of racks inside the storage accordingly

Aisle width — [Enabled if Number of racks is: calculated based on dimensions] Here you can define the width of a single aisle.

Number of racks — [Enabled if Number of racks is: defined explicitly] Here you can specify how many racks there are in a single rack storage.

Number of bays is — Here you can select how the number of bays in your storage is defined. It is either:

  • calculated based on dimensions — you define the dimensions of the bay width and the dimensions of the storage itself, and AnyLogic calculates the number of bays inside the rack accordingly
  • defined explicitly — you specify the Number of bays in the corresponding property below

Bay width — [Enabled if Number of bays is: defined explicitly] Here you can define the width of a single bay. The value will be used to calculate the number of bays in the rack.

Number of bays — [Enabled if Number of bays is: calculated based on dimensions] Here you can specify how many bays there are in a single rack.

Create storage network — Click this button to draw a network of paths and point nodes running through the aisles of the storage and along the storage perimeter. Path-guided transporters and agents can use these paths to approach the storage.

Rack

Number of shelves — The number of vertical shelves in the rack storage.

Cells per slot — The number of cells in the depth of each slot.

Shelf height — The height of a shelf.

Set speed inside slot — Select this option to specify the speed of agent's movement inside the slot. If the option is not selected, the agent moves with its own speed or with the speed of the seized resource.

Speed inside slot — [Enabled if Set speed inside slot is selected] The speed of agent's movement inside the slot.

Actions

On agent storage — Code that will be executed when the agent (material item) is stored in the cell.
Local variables:
T agent — agent (material item)
StorageCell cell — cell

On agent retrieval — Code that will be executed when the agent (material item) is retrieved from the cell by the Retrive block or by calling the retrieve() function of storage.
Local variables:
T agent — agent (material item)
StorageCell cell — cell

Appearance

Shelves color — [Enabled if Rack type: Selective]Color of the shelves.

Frame color — Color of the frame.

Occupied cells animation — Here you can choose how to display agents inside the storage during model run.

  • color indication (fast) — individual agent animation is hidden, and the cell is filled with the agent color or a blend of vertically stored agents' colors: this allows for a more informing view of multi-level racks and has much better performance for large-scale warehouses. You can set the agent's color by calling agent.setColor() function.
  • agent animation — individual agent animation is placed in the center of the cell

Draw upright posts in 3D — [Enabled if Show in: 2D and 3D or 3D only option is selected] Deselect this option if you do not need to draw vertical elements of the frame in 3D. Only shelves will be drawn in this case.

Bays between posts — [Enabled if Show in: 2D and 3D or 3D only option is selected] The number of bays between frame posts if the posts are drawn in 3D. It does not affect the 2D animation of pallet rack.

Position and size

Level — a level where this rack storage is located.

X — X-coordinate of the rack storage (upper left corner).

Y — Y-coordinate of the rack storage (upper left corner).

Z — Z-coordinate of the rack storage. It's relative to the Z-coordinate of the level where this rack storage lives.

Rotation — Rotation angle of the rack storage in XY plane.

Storage length — [Enabled if Number of racks: defined explicitly] The length of the storage rack.

Storage width — [Enabled if Number of bays: defined explicitly] The width of the storage rack.

Access zone — Width of a zone adjacent to the rack storage where any network path passing through it can be used by transporters or agents to approach the rack for storage or retrieval.

Advanced

Show in — Here you can choose whether you want the storage rack shape to be displayed both In 2D and 3D animation, or in 2D only, or in 3D only.

Show name — If selected, the name of the storage rack shape is displayed on the graphical diagram.

Functions

You can dynamically modify storage properties at model runtime using the following API.

General
Function Description
Storage() A constructor to create a new storage with default parameters. You can change the parameters programmatically before markup initialization.
Any operations with cells must be done after markup initialization.
RackUnitAggregator getStorageSystem() Returns the storage system this storage belongs to.
void setRackType(RackType type) Sets the rack type: either selective or drive-in.

type — the rack type: either RACK_TYPE_DRIVE_IN or RACK_TYPE_SELECTIVE.
RackPlacement getRackPlacement() Returns the rack placement of this storage. Valid values are:

RACK_PLACEMENT_STAND_ALONE — stand-alone
RACK_PLACEMENT_BACK_TO_BACK — back-to-back
void setRackPlacement(RackPlacement rackPlacement) Sets the rack placement of this storage: either stand-alone or back-to-back.

rackPlacement — the rack placement: either RACK_PLACEMENT_STAND_ALONE or RACK_PLACEMENT_BACK_TO_BACK.
Storage configuration
Function Description
int getNumberOfRacks() Returns the number of racks in this storage.
void setNumberOfRacks(int numberOfRacks) Sets the number of racks in this storage. Cannot be called after markup initialization.

numberOfRacks — new number of racks
int getNumberOfBays() Returns the number of bays per rack.
void setNumberOfBays(int numberOfBays) Sets the number of bays per rack. Cannot be called after markup initialization.

numberOfBays — new number of bays
int getNumberOfCellsPerSlot() Returns the number of cells per slot.
void setNumberOfCellsPerSlot(int numberOfCells) Sets number of cells per slot. Cannot be called after markup initialization.

numberOfCells — new number of cells
int getNumberOfShelves() Returns the number of shelves per rack.
void setNumberOfShelves(int numberOfShelves) Sets number of shelves per rack. May not be called after initialization of markup.

numberOfShelves — new number of shelves
double getRackDepth(LengthUnits units)

Returns the rack depth in specified length units.

units — a constant defining length units

void setRackDepth(double rackDepth, LengthUnits units) Sets the rack depth in specified length units. Cannot be called after markup initialization.

rackDepth — new rack depth
units — a constant defining length units
double getShelfHeight(LengthUnits units) Returns the height of a shelf in specified length units.

units — a constant defining length units
void setShelfHeight(double shelfHeight, LengthUnits units) Sets the height of a shelf in specified length units. Cannot be called after markup initialization.

shelfHeight — new shelf height
units — a constant defining length units
double getCellWidth(LengthUnits units) Returns the cell width in specified length units.

units — a constant defining length units
void setCellWidth(double cellWidth, LengthUnits units) Sets the cell width in specified length units. Cannot be called after markup initialization.

cellWidth — new cell width
units — a constant defining length units
double getAisleWidth(LengthUnits units) Returns the aisle width in specified length units.

units — a constant defining length units
void setAisleWidth(double aisleWidth, LengthUnits units) Sets the aisle width in specified length units. Cannot be called after markup initialization.

aisleWidth — new aisle width
units — a constant defining length units
double getAccessZone(LengthUnits units) Returns the width of access zone in specified length units.

units — a constant defining length units
void setAccessZone(double zoneWidth, LengthUnits units) Sets the width of access zone in specified length units. Cannot be called after markup initialization.

zoneWidth — new width of access zone
units — a constant defining length units
Cells

All functions listed here can be called only after markup initialization.

Function Description
StorageCell getCell(Agent agent) Returns the cell that contains the specified agent.

agent — an agent (material item)
StorageCell getCell(int rack, int bay, int shelf, int deepPosition) Returns the specified cell.

rack — index of rack
bay — index of bay
shelf — index of shelf
deepPosition — index of cell
List<StorageCell> getCells() Returns a list of cells ordered according to the storage type.
StorageCell getRandomFreeCell() Returns the next cell available for reservation in a random slot from the storage.
List<StorageCell> freeCells(int rack) Returns a list of all free cells in the specified rack.

rack — index of rack
List<StorageCell> freeCells(int rack, int bay) Returns a list of all free cells in the specified bay.

rack — index of rack
bay — index of bay
List<StorageCell> freeCells(int rack, int bay, int shelf) Returns a list of all free cells in the specified shelf.

rack — index of rack
bay — index of bay
shelf — index of shelf
int nFreeCells() Returns the total number of free cells in the storage.
int nFreeCells(int rack) Returns a total number of free cells in the specified rack.

rack — index of rack
int nFreeCells(int rack, int bay) Returns a total number of free cells in the specified bay.

rack — index of rack
bay — index of bay
int nFreeCells(int rack, int bay, int shelf) Returns a total number of free cells in the specified shelf.

rack — index of rack
bay — index of bay
shelf — index of shelf
Slot

All functions listed here can be called only after markup initialization.

Function Description
StorageSlot getSlot(int rack, int bay, int shelf) Returns the specified slot.

rack — index of rack
bay — index of bay
shelf — index of shelf

Slot has its own set of functions that you can use to get its location in the storage.

In-slot speed

All functions listed here can be called only after markup initialization.

Function Description
boolean isSpecifiedInslotSpeed() Returns true if specific in-slot speed was enabled and false otherwise.
void setSpecifiedInslotSpeed(boolean enabled) Enables specific in-slot speed if the argument is true and disables if the argument is false.

enabled — if true, specific in-slot speed will be enabled; if false — disabled.
double getInslotSpeed(SpeedUnits units) Returns in-slot speed in specified speed units.

units — a constant defining speed units
void setInslotSpeed(double speed, SpeedUnits units) Sets in-slot speed in specified speed units.

speed — new in-slot speed value
units — a constant defining speed units
Agents

All functions listed here can be called only after markup initialization.

Function Description
int size() Returns the number of stored agents.
List<Agent> getAgents() Returns a list of agents stored in the storage, ordered according to storage type.
Agent getRandomAgent() Returns a random agent stored in the storage. If the storage is empty, returns null.
boolean contains(Agent agent) Returns true if the given agent is stored in the storage and false otherwise.
Agent getAgentInCell(int rack, int bay, int shelf, int deepPosition) Returns the agent stored in the given cell.

rack — index of rack
bay — index of bay
shelf — index of shelf
deepPosition — index of cell
Reservation

All functions listed here can be called only after markup initialization.

Function Description
boolean hasSpace(int rack, int bay, int shelf) Returns true if the given slot has cells available for reservation and false otherwise.

rack — index of rack
bay — index of bay
shelf — index of shelf
boolean hasSpace() Returns true if the storage has cells available for reservation and false otherwise.
int nReserved() Returns the number of reserved (but not occupied) cells.
List<StorageCell> reservedCells(int rack, int bay, int shelf) Returns a list of reserved cells located in the given slot.

rack — index of rack
bay — index of bay
shelf — index of shelf
List<StorageCell> reservedCells(int rack, int bay) Returns a list of reserved cells located in the given bay.

rack — index of rack
bay — index of bay
void setReservation(Agent agent, int rack, int bay, int shelf) Reserves a cell for the given agent in the given slot. The actual cell where the agent will be placed is determined at the moment of placement.

agent — agent (material item)
rack — index of rack
bay — index of bay
shelf — index of shelf
void setReservation(Agent agent, int rack, int bay) Reserves a cell for the given agent in the given bay. The actual cell where the agent will be placed is determined at the moment of placement.

agent — agent (material item)
rack — index of rack
bay — index of bay
void cancelReservation(Agent agent) Discards any reservations made for the given agent.

agent — agent (material item)
Storing operation

All functions listed here can be called only after markup initialization.

Function Description
void store(Agent agent) Stores the given agent in the storage. If there are no cells available for reservation, an error will occur.

agent — agent (material item)
void store(Agent agent, int rack, int bay, int shelf) Stores the given agent in the given slot. If there are no cells available for reservation, an error will occur.

agent — agent (material item)
rack — index of rack
bay — index of bay
shelf — index of shelf
void store(Agent agent, int rack, int bay) Stores the given agent in the given bay. If there are no cells available for reservation, an error will occur.

agent — agent (material item)
rack — index of rack
bay — index of bay
void store(Agent agent, int rack) Stores the given agent in the given rack. If there are no cells available for reservation, an error will occur.

agent — agent (material item)
rack — index of rack
Retrieving operation

All functions listed here can be called only after markup initialization.

Function Description
Agent retrieve(Agent agent) Retrieves and returns the previously stored agent from the storage.

agent — agent (material item)
Agent retrieve(int rack, int bay, int shelf) Retrieves and returns the next available agent from the specified slot.

rack — index of rack
bay — index of bay
shelf — index of shelf
Agent retrieve(int rack, int bay) Retrieves and returns the next agent from the specified bay.

rack — index of rack
bay — index of bay
Agent retrieve(int rack) Retrieves and returns the next agent from the specified rack.

rack — index of rack
Storage as obstacle
Function Description
boolean isObstacle() Returns true if the racks of this storage are considered obstacles by pedestrians and transporters with free space navigation. Otherwise, returns false.
void setObstacle(boolean isObstacle) Sets the racks of this storage as obstacles for pedestrians and transporters with free space navigation.

isObstacle — specify true to turn the racks into obstacles; specify false otherwise.
Storage position
Function Description
double getX() Returns the X coordinate of this storage.
void setX(double x) Sets the X coordinate of this storage. Cannot be called after markup initialization.

x — new X-coordinate of the storage
double getY() Returns the Y coordinate of this storage.
void setY(double y) Sets the Y coordinate of this storage. Cannot be called after markup initialization.

y — new Y-coordinate of the storage
double getZ() Returns the Z coordinate of this storage.
void setZ(double z) Sets the Z coordinate of this storage. Cannot be called after markup initialization.

z — new Z-coordinate of the storage
double getRotation() Returns the rotation of the storage in radians.
void setRotation(double rotation) Sets the rotation of the storage. Cannot be called after markup initialization.

rotation — new rotation value in radians
Storage appearance
Function Description
Color getShelvesColor() Returns the color of rack shelves.
void setShelvesColor(Color shelvesColor) Sets the color of rack shelves. This function doesn't work for storages with drive-in rack type.

shelvesColor — new color of the shelves
Color getFrameColor() Returns the color of the rack frame.
void setFrameColor(Color frameColor) Sets the color of the rack frame.

frameColor — new color of the frame
Statistics
Function Description
int capacity() Returns the maximum possible number of agents that can be stored in this storage. Deactivated cells are excluded from the result.
int nStored() Returns the total number of stored agents. May be reset by calling resetStats() function.
int nRetrieved() Returns the total number of retrieved agents. May be reset by calling resetStats() function.
double utilization() Returns the storage's utilization. Utilization is a double value in range [0, 1] that is calculated as a ratio of occupied cells to capacity.
void resetStats() Resets the statistics of the storage: the number of stored agents and the number of retrieved agents.

Slot functions

This section contains functions of the StorageSlot class. They can be called only after markup initialization.

Location in storage
Function Description
Storage getStorage() Returns the rack storage that this slot belongs to.
int getRack() Returns the index of the rack that this slot belongs to.
int getShelf() Returns the index of the shelf that this slot belongs to.
int getBay() Returns the index of the bay that this slot belongs to.

Cell functions

This section contains functions of the StorageCell class. They can be called only after markup initialization.

Location in storage
Function Description
Storage getStorage() Returns the rack storage that this cell belongs to.
int getRack() Returns the index of the rack that this cell belongs to.
int getShelf() Returns the index of the shelf that this cell belongs to.
int getBay() Returns the index of the bay that this cell belongs to.
int getDeepPosition() Returns the index of this cell in the slot.
Agent getAgent() Returns the agent that occupies this cell or null if the cell is not occupied.

agent — agent (material item)
Storing and retrieving
Function Description
boolean isAvailableToStore() Returns true if the cell is both open for reservation and accessible, false otherwise.
boolean isAvailableToRetrieve() Returns true if the cell is both accessible and contains an agent, false otherwise.
void store(Agent agent) Stores the specified agent in this cell. The agent is stored in the cell immediately and without animation. The specified agent cannot have another cell reserved, and this cell must be available for reservations.

agent — agent (material item)
Agent retrieve() Removes and returns the agent that currently occupies this cell. The cell must not be empty.
Reservation
Function Description
boolean isFree() Returns true if the cell is both empty and not reserved by any agent, false otherwise.
void setReservation(Agent agent) Reserves this cell for the specified agent. This cell must not be reserved by any other agent when this function is called, otherwise an error message will be displayed.

agent — agent (material item)
Agent cancelReservation() Cancels reservation for the agent that reserved this cell and returns this agent. The cell must be explicitly reserved by any agent.
Cell deactivation
Function Description
boolean isActive() Returns true if the cell is not deactivated and operates normally, false otherwise.
void deactivate() Deactivates the cell and disallows all operations with it. Agents (material items) can be transported through the areas where cells were deactivated. This function may be useful to model rack storages with irregularly placed empty spaces. Once deactivated, the cell cannot be activated again during runtime.
How can we improve this article?