Criticality
Criticality: sandpiles, forest fires, absorbing-state transitions, learners at the edge, and avalanches.
ActiveFieldElement(label, visual=None, *, rho=0.5, nu=1.0, a=-1.0, b=1.0, c=1.0, d=1.0, e=0.2, f=0.0, g=0.0)
Bases: Element
Site of the Langevin equation of directed percolation with a conserved field, an activity rho and a field nu.
The activity grows at the rate a + b nu, saturates, diffuses, and fluctuates with the multiplicative noise
e sqrt(rho) of an absorbing state, rho_t = (a + b nu) rho - c rho^2 + d laplacian(rho) + e sqrt(rho) eta. The
field diffuses, gains f, and is consumed by the activity, nu_t = laplacian(nu) + f - g rho. Both stay
nonnegative.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the site or the field. |
required |
visual
|
VisualSpec | None
|
How the site is drawn, or |
None
|
rho
|
Annotated[float, StateSpec()]
|
The initial activity. |
0.5
|
nu
|
Annotated[float, StateSpec()]
|
The initial field. |
1.0
|
a
|
Annotated[float, ParameterSpec()]
|
The linear growth rate of the activity. |
-1.0
|
b
|
Annotated[float, ParameterSpec()]
|
The growth of the activity per unit of the field. |
1.0
|
c
|
Annotated[float, ParameterSpec()]
|
The saturation of the activity. |
1.0
|
d
|
Annotated[float, ParameterSpec()]
|
The diffusion coefficient of the activity. |
1.0
|
e
|
Annotated[float, ParameterSpec()]
|
The amplitude of the noise. |
0.2
|
f
|
Annotated[float, ParameterSpec()]
|
The input of the field. |
0.0
|
g
|
Annotated[float, ParameterSpec()]
|
The consumption of the field by the activity. |
0.0
|
Attributes:
| Name | Type | Description |
|---|---|---|
default_visual_ |
The visual of the site when it sets none. |
Examples:
>>> from skcomplex.models.physics.criticality import ActiveFieldElement
>>> ActiveFieldElement('site').e
0.2
Source code in src/skcomplex/models/physics/criticality/_absorbing.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | |
AvalancheInteraction(label, *, target, state='height', threshold=4, mode='redistribute')
Bases: CascadeInteraction
Slowly driven sandpile: every step drops one grain on a random site, and the full sites topple in avalanches.
A site that holds threshold grains topples. In the mode 'redistribute' it sends one grain to each of its
neighbours, as in the Bak-Tang-Wiesenfeld sandpile, and in the mode 'random' every grain goes to a neighbour drawn
at random, as in the Manna sandpile. Grains that topple over a fixed edge leave the pile, and every avalanche is
recorded as an event under the label of the interaction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the interaction and of its avalanche events. |
required |
target
|
Annotated[str, RoleSpec()]
|
The path of the lattice group of sites. |
required |
state
|
str
|
The name of the state that holds the grains. |
'height'
|
threshold
|
int
|
The number of grains at which a site topples. |
4
|
mode
|
str
|
|
'redistribute'
|
Examples:
>>> from skcomplex.models.physics.criticality import AvalancheInteraction
>>> AvalancheInteraction('avalanche', target='pile', threshold=2, mode='random').share
1
Source code in src/skcomplex/models/physics/criticality/_avalanche.py
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | |
CracklingNoiseAnalysis(variables=None, *, threshold=0.0, durations=(), min_count=10, min_duration=1, size_exponent=None, duration_exponent=None)
Bases: EventAnalysis
Crackling-noise scaling of the avalanches of an activity series or of the relaxations of a lattice.
It finds the avalanches as the event analysis of kind 'excursions', then fits the exponent gamma of the mean
size against the duration, <S>(T) ~ T^gamma, predicts it as (tau_T - 1) / (tau_S - 1) from the exponents of
the size and duration laws, such as those FitAnalysis(law='power') fits, and collapses the mean shapes of the
chosen durations, which agree after scaling at a critical point.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
variables
|
Sequence[str] | None
|
The one variable of a trajectory to read, or |
None
|
threshold
|
float
|
The activity an avalanche exceeds at every step, subtracted from its profile. |
0.0
|
durations
|
Sequence[int]
|
The durations whose mean shapes are compared. |
()
|
min_count
|
int
|
The fewest avalanches of a duration used in the fit of the mean size. |
10
|
min_duration
|
int
|
The shortest duration used in the fit of the mean size. |
1
|
size_exponent
|
float | None
|
The exponent |
None
|
duration_exponent
|
float | None
|
The exponent |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
exponent_ |
The exponent |
|
predicted_ |
The exponent |
|
mean_shapes_ |
The mean shape of every chosen duration, scaled to unit mean height, on a grid of 0 to 1. |
|
shape_spread_ |
The mean over the inner 80 percent of the scaled time of the relative difference between the largest and
the smallest mean shape of the chosen durations, |
Examples:
>>> from skcomplex.models.physics.criticality import CracklingNoiseAnalysis
>>> activity = [0, 1, 0, 1, 2, 1, 0, 1, 0, 2, 3, 2, 0]
>>> crackling = CracklingNoiseAnalysis(min_count=1).check().prepare(activity).run()
>>> round(crackling.exponent_, 2)
1.55
Source code in src/skcomplex/models/physics/criticality/_crackling_noise.py
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | |
FireInteraction(label, *, target, neighborhood=NEAREST)
Bases: LocalRuleInteraction
Stochastic rule of the Drossel-Schwabl forest fire on a cover of 0 for empty, 1 for a tree, and 2 for burning.
Every step a tree catches fire from a burning neighbour or from lightning with the probability lightning of the
site, a burning site becomes empty, and a tree grows on an empty site with the probability growth of the site.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the interaction, unique among the parts of its system. |
required |
target
|
Annotated[str, RoleSpec()]
|
The path of the lattice or network group of sites. |
required |
neighborhood
|
BaseNeighborhood
|
The neighbours a fire spreads to, the von Neumann neighbourhood of a square lattice, the six neighbours of a triangular lattice, or the neighbours of a node, each with the site itself. |
NEAREST
|
Examples:
>>> from skcomplex.models.physics.criticality import FireInteraction
>>> FireInteraction('fire', target='forest').stochastic
True
Source code in src/skcomplex/models/physics/criticality/_fire.py
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | |
ForestElement(label, visual=None, *, cover=0, growth=0.05, lightning=0.0001)
Bases: Element
Site of the Drossel-Schwabl forest fire: empty at 0, a tree at 1, or burning at 2.
A FireInteraction grows trees on empty sites with probability growth, sets them on fire from a burning
neighbour or from lightning with probability lightning, and empties burning sites.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the site or the lattice group. |
required |
visual
|
VisualSpec | None
|
How the element is drawn, or |
None
|
cover
|
Annotated[float, StateSpec(domain=NN)]
|
The initial cover, 0, 1, or 2. |
0
|
growth
|
Annotated[float, ParameterSpec(domain=closed_open(0, oo))]
|
The probability that a tree grows on an empty site per step. |
0.05
|
lightning
|
Annotated[float, ParameterSpec(domain=closed_open(0, oo))]
|
The probability that lightning strikes a tree per step. |
0.0001
|
Examples:
>>> from skcomplex.models.physics.criticality import ForestElement
>>> ForestElement('site').growth
0.05
Source code in src/skcomplex/models/physics/criticality/_forest.py
43 44 45 46 47 48 49 50 51 52 53 54 55 | |
LearnerElement(label, visual=None, *, incentive=0.0, spin=1.0, temperature=1.0, fitness=0.0, reward=0.0, memory=0.75, max_temperature=2.0, couplings=None, evolving=True, settling=2)
Bases: Element
Agent of the evolutionary Sherrington-Kirkpatrick game, who learns a binary action and may be replaced.
The agent keeps an incentive Q, the value of action +1, and plays the action s = ±1 by the softmax policy at
its temperature T. Every step the incentive becomes (1 - alpha) Q + alpha h for the local field
h = Σ_j J_ij s_j, and the fitness is s Q. When the agent evolves and its fitness is the least of the group,
it is replaced by a newcomer with no incentive and a temperature drawn uniformly up to max_temperature, who
learns from the field at once. The reward s h of the last actions is kept.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the agent or the group. |
required |
visual
|
VisualSpec | None
|
How the element is drawn, or |
None
|
incentive
|
Annotated[float, StateSpec()]
|
The initial incentive |
0.0
|
spin
|
Annotated[float, StateSpec(domain=ZZ)]
|
The initial action, -1 or 1. |
1.0
|
temperature
|
Annotated[float, StateSpec(domain=closed_open(0, oo))]
|
The initial temperature |
1.0
|
fitness
|
Annotated[float, StateSpec()]
|
The initial fitness |
0.0
|
reward
|
Annotated[float, StateSpec()]
|
The initial reward |
0.0
|
memory
|
Annotated[float, ParameterSpec(domain=closed_open(0, oo))]
|
The weight |
0.75
|
max_temperature
|
Annotated[float, ParameterSpec(domain=open(0, oo))]
|
The largest temperature of a newcomer. |
2.0
|
couplings
|
ArrayLike | None
|
The coupling matrix |
None
|
evolving
|
bool
|
Whether the least fit agent is replaced. |
True
|
settling
|
int
|
The number of steps of learning alone after every replacement, so replacements happen when |
2
|
Examples:
>>> from skcomplex.models.physics.criticality import LearnerElement
>>> LearnerElement('agent').memory
0.75
Source code in src/skcomplex/models/physics/criticality/_evolutionary_learning.py
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | |
LearningAgentElement(label, visual=None, *, sigma=1.0, Q=0.0, alpha=0.5, temperature=0.5, couplings=None)
Bases: Element
Agent of the SK game that plays an action of ±1 from a softmax policy over its incentive to play +1.
The incentive follows the reinforcement rule Q(t + 1) = (1 - alpha) Q(t) + alpha sum_j J_ij sigma_j(t), the
discounted reward of playing +1, and the agent plays sigma = ±1 with probability 1 / (1 + exp(-+2 Q / T)).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the agent or the group. |
required |
visual
|
VisualSpec | None
|
How the element is drawn, or |
None
|
sigma
|
Annotated[float, StateSpec(domain=ZZ)]
|
The initial action, -1 or 1. |
1.0
|
Q
|
Annotated[float, StateSpec()]
|
The initial incentive. |
0.0
|
alpha
|
Annotated[float, ParameterSpec(domain=open(0, oo))]
|
The memory parameter, the weight of the latest reward. |
0.5
|
temperature
|
Annotated[float, ParameterSpec(domain=open(0, oo))]
|
The exploration temperature |
0.5
|
couplings
|
ArrayLike | None
|
The coupling matrix |
None
|
Examples:
>>> from skcomplex.models.physics.criticality import LearningAgentElement
>>> LearningAgentElement('agent').alpha
0.5
Source code in src/skcomplex/models/physics/criticality/_learning.py
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | |
SandpileCellElement(label, visual=None, *, height=0)
Bases: Element
Site of a sandpile, which holds a number of grains.
An AvalancheInteraction drops the grains and topples the sites that hold too many.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
label
|
str
|
The label of the site or the lattice group. |
required |
visual
|
VisualSpec | None
|
How the site is drawn, or |
None
|
height
|
Annotated[float, StateSpec(domain=NN)]
|
The initial number of grains. |
0
|
Attributes:
| Name | Type | Description |
|---|---|---|
default_visual_ |
The visual of the site when it sets none. |
Examples:
>>> from skcomplex.models.physics.criticality import SandpileCellElement
>>> SandpileCellElement('site').height
0
Source code in src/skcomplex/models/physics/criticality/_sandpile_cell.py
39 40 41 42 43 44 45 46 47 | |
directed_percolation_langevin(shape=(64, 64), *, a=-1.0, b=1.0, c=1.0, d=1.0, e=0.2, f=0.0, g=0.0, energy=1.2, density=0.5, random_state=0)
Return the Langevin field theory of an absorbing-state transition, an active density fed by an energy field.
The active density rho grows at the local rate a + b nu, saturates through -c rho^2, spreads with the
diffusivity d, and fluctuates with the multiplicative noise e sqrt(rho), which vanishes in the absorbing state
rho = 0. The energy field nu diffuses, gains the drive f, and loses the dissipation g rho, so
rho_t = (a + b nu) rho - c rho^2 + d laplacian(rho) + e sqrt(rho) xi and nu_t = laplacian(nu) + f - g rho
(Tian et al., Eqs. 3-4). Both fields stay nonnegative. Without drive and dissipation the energy is a fixed control
parameter: below the threshold nu_c = -a / b activity dies out, and above it the density settles near
(a + b nu) / c.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shape
|
Sequence[int]
|
The number of sites along every axis of the periodic lattice. |
(64, 64)
|
a
|
float
|
The bare growth rate of the activity. |
-1.0
|
b
|
float
|
The gain of the growth rate per unit of energy. |
1.0
|
c
|
float
|
The saturation of the activity. |
1.0
|
d
|
float
|
The diffusivity of the activity. |
1.0
|
e
|
float
|
The amplitude of the multiplicative noise. |
0.2
|
f
|
float
|
The drive of the energy. |
0.0
|
g
|
float
|
The dissipation of the energy per unit of activity. |
0.0
|
energy
|
float
|
The initial energy at every site. |
1.2
|
density
|
float
|
The mean initial activity, drawn uniformly between 0 and twice this value. |
0.5
|
random_state
|
int | Generator | None
|
The seed or generator of the initial activity. |
0
|
Returns:
| Name | Type | Description |
|---|---|---|
system |
System
|
The model, with the activity |
Examples:
>>> from skcomplex.models.physics.criticality import directed_percolation_langevin
>>> float(directed_percolation_langevin((8, 8), energy=0.5).elements[0].values['nu'].mean())
0.5
Source code in src/skcomplex/models/physics/criticality/_absorbing.py
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | |
evolutionary_sk_game(n_agents=256, *, memory=0.75, temperature=None, max_temperature=2.0, random_state=0)
Return the evolutionary Sherrington-Kirkpatrick game, which self-organises to the edge of ergodicity breaking.
After Lesmana et al. (2026, arXiv 2604.15669), N agents play ±1 on a Sherrington-Kirkpatrick landscape with
symmetric Gaussian couplings of variance 1 / N. Each learns the incentive of its actions with memory alpha and
plays by a softmax policy at its own temperature, and the least fit agent is replaced, as in the Bak-Sneppen
model, by a newcomer whose temperature is drawn uniformly on [0, max_temperature]. The temperatures evolve to the
edge between ergodic and frozen learning, the replacement cascades have sizes distributed as S^(-3/2), and the
mean reward exceeds that of the game at any fixed temperature. With a fixed temperature, no agent is replaced and
the model is the Sherrington-Kirkpatrick game of Galla and Farmer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_agents
|
int
|
The number of agents |
256
|
memory
|
float
|
The weight |
0.75
|
temperature
|
ArrayLike | None
|
The temperature of every agent, or one per agent, of the game without replacement, or |
None
|
max_temperature
|
float
|
The largest temperature of a newcomer, and of the initial temperatures drawn uniformly. |
2.0
|
random_state
|
int | Generator | None
|
The seed or generator of the couplings, the initial actions, and the initial temperatures. |
0
|
Returns:
| Name | Type | Description |
|---|---|---|
system |
System
|
The model, with the group |
Examples:
>>> from skcomplex.models.physics.criticality import evolutionary_sk_game
>>> agents = evolutionary_sk_game(16).elements[0]
>>> couplings = agents.values['couplings']
>>> agents.size, bool((couplings == couplings.T).all()), float(couplings.trace())
(16, True, 0.0)
Source code in src/skcomplex/models/physics/criticality/_evolutionary_learning.py
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | |
forest_fire(shape=(100, 100), *, growth=0.05, lightning=0.0001, density=0.5, random_state=0)
Return the Drossel-Schwabl forest fire, where slow growth and rare lightning give fires of every size.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shape
|
Sequence[int]
|
The number of rows and columns. |
(100, 100)
|
growth
|
float
|
The probability that a tree grows on an empty site per step. |
0.05
|
lightning
|
float
|
The probability that lightning strikes a tree per step. |
0.0001
|
density
|
float
|
The initial fraction of sites with a tree. |
0.5
|
random_state
|
int | Generator | None
|
The seed or generator of the initial forest. |
0
|
Returns:
| Name | Type | Description |
|---|---|---|
system |
System
|
The model, with the covers |
Examples:
>>> from skcomplex.models.physics.criticality import forest_fire
>>> forest_fire((10, 10)).elements[0].values['growth']
0.05
Source code in src/skcomplex/models/physics/criticality/_criticality.py
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | |
hexagonal_forest_fire(shape=(80, 80), *, graph=None, growth=0.02, lightning=1e-05, density=0.5, cover=None, random_state=0)
Return the Drossel-Schwabl forest fire on a triangular lattice of hexagonal cells, or on the nodes of a graph.
Every site of the periodic triangular lattice has six neighbours, and every node of a graph has the neighbours along its edges. Slow growth and rare lightning give fires of every size.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shape
|
Sequence[int]
|
The number of rows and columns of the triangular lattice, unused on a graph. |
(80, 80)
|
graph
|
Graph | None
|
The graph whose nodes are the sites, or |
None
|
growth
|
float
|
The probability that a tree grows on an empty site per step. |
0.02
|
lightning
|
float
|
The probability that lightning strikes a tree per step. |
1e-05
|
density
|
float
|
The initial fraction of sites with a tree. |
0.5
|
cover
|
Sequence[float] | None
|
The initial cover of every site, 0 for empty, 1 for a tree, and 2 for burning, in lattice shape or node
order, or |
None
|
random_state
|
int | Generator | None
|
The seed or generator of the initial forest. |
0
|
Returns:
| Name | Type | Description |
|---|---|---|
system |
System
|
The model, with the covers |
Examples:
>>> import networkx as nx
>>> from skcomplex.models.physics.criticality import hexagonal_forest_fire
>>> hexagonal_forest_fire((10, 10)).elements[0].check().prepare().size_
100
>>> hexagonal_forest_fire(graph=nx.cycle_graph(12)).elements[0].check().prepare().size_
12
Source code in src/skcomplex/models/physics/criticality/_criticality.py
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | |
manna_sandpile(shape=(32, 32), *, random_state=0)
Return the Manna sandpile, a stochastic sandpile of another universality class than Bak-Tang-Wiesenfeld.
The pile starts from random stable heights of 0 or 1 grain, and its avalanches are recorded as avalanche
events with their sizes, durations, and areas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shape
|
Sequence[int]
|
The number of rows and columns. |
(32, 32)
|
random_state
|
int | Generator | None
|
The seed or generator of the initial heights. |
0
|
Returns:
| Name | Type | Description |
|---|---|---|
system |
System
|
The model, with the heights |
Examples:
>>> from skcomplex.models.physics.criticality import manna_sandpile
>>> manna_sandpile((10, 10)).elements[0].check().prepare().size_
100
Source code in src/skcomplex/models/physics/criticality/_criticality.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | |
sandpile(shape=(50, 50), *, random_state=0)
Return the Bak-Tang-Wiesenfeld sandpile on a lattice with open edges, started from random stable heights.
Its avalanches are recorded as avalanche events with their sizes, the number of topplings, their durations,
and their areas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shape
|
Sequence[int]
|
The number of rows and columns. |
(50, 50)
|
random_state
|
int | Generator | None
|
The seed or generator of the initial heights. |
0
|
Returns:
| Name | Type | Description |
|---|---|---|
system |
System
|
The model, with the heights |
Examples:
>>> from skcomplex.models.physics.criticality import sandpile
>>> sandpile((10, 10)).elements[0].check().prepare().size_
100
Source code in src/skcomplex/models/physics/criticality/_criticality.py
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | |
sk_game(n_agents=256, *, alpha=0.5, temperature=0.5, random_state=0)
Return the SK game, reinforcement learners whose rewards come from quenched Sherrington-Kirkpatrick couplings.
Every agent plays sigma_i = ±1 and earns sigma_i sum_j J_ij sigma_j, with symmetric Gaussian couplings of mean
0, variance 1 / N, and zero diagonal. It discounts its rewards with the memory alpha into the incentive Q_i
and plays from a softmax policy at the temperature T (Lesmana et al., Eqs. 1-3). All agents start with zero
incentives, so their first actions are random, and update in parallel. At low temperature the agents freeze into
one of many ordered states with a high collective reward, and at high temperature they explore noisily with a low
one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_agents
|
int
|
The number of agents |
256
|
alpha
|
float
|
The memory parameter. |
0.5
|
temperature
|
float
|
The exploration temperature of every agent. |
0.5
|
random_state
|
int | Generator | None
|
The seed or generator of the couplings and of the initial actions. |
0
|
Returns:
| Name | Type | Description |
|---|---|---|
system |
System
|
The model, with the actions |
Examples:
>>> from skcomplex.models.physics.criticality import sk_game
>>> couplings = sk_game(10).elements[0].values['couplings']
>>> bool((couplings == couplings.T).all())
True
Source code in src/skcomplex/models/physics/criticality/_learning.py
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | |