occam-directed-graphs 3.0.34 → 3.0.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,422 @@
1
+ "use strict";
2
+
3
+ import { arrayUtilities } from "necessary";
4
+
5
+ import Edge from "./edge";
6
+ import Vertex from "./vertex";
7
+
8
+ import { vertexNamesFromVertices, orderVertices } from "./utilities/vertex";
9
+
10
+ const { last } = arrayUtilities;
11
+
12
+ export default class DirectedAcyclicGraph {
13
+ constructor(vertexMap) {
14
+ this.vertexMap = vertexMap;
15
+ }
16
+
17
+ isEmpty() {
18
+ const vertices = this.getVertices(),
19
+ verticesLength = vertices.length,
20
+ empty = (verticesLength === 0);
21
+
22
+ return empty;
23
+ }
24
+
25
+ getVertices() {
26
+ const vertexMapValues = Object.values(this.vertexMap),
27
+ vertices = vertexMapValues; ///
28
+
29
+ return vertices;
30
+ }
31
+
32
+ getVertexNames() {
33
+ const vertexMapKeys = Object.keys(this.vertexMap),
34
+ vertexNames = vertexMapKeys; ///
35
+
36
+ return vertexNames;
37
+ }
38
+
39
+ getVertexByVertexName(vertexName) {
40
+ const vertexPresent = this.isVertexPresentByVertexName(vertexName),
41
+ vertex = vertexPresent ?
42
+ this.vertexMap[vertexName] :
43
+ null;
44
+
45
+ return vertex;
46
+ }
47
+
48
+ getImmediatePredecessorVertexNamesByVertexName(vertexName) {
49
+ const vertex = this.getVertexByVertexName(vertexName),
50
+ immediatePredecessorVertexNames = vertex.getImmediatePredecessorVertexNames();
51
+
52
+ return immediatePredecessorVertexNames;
53
+ }
54
+
55
+ getImmediateSuccessorVertexNamesByVertexName(vertexName) {
56
+ const vertex = this.getVertexByVertexName(vertexName),
57
+ immediateSuccessorVertexNames = vertex.getImmediateSuccessorVertexNames();
58
+
59
+ return immediateSuccessorVertexNames;
60
+ }
61
+
62
+ getPredecessorVertexNamesByVertexName(vertexName) {
63
+ const vertex = this.getVertexByVertexName(vertexName),
64
+ predecessorVertexNames = vertex.getPredecessorVertexNames();
65
+
66
+ return predecessorVertexNames;
67
+ }
68
+
69
+ getSuccessorVertexNamesByVertexName(vertexName) {
70
+ const vertex = this.getVertexByVertexName(vertexName),
71
+ successorVertexNames = vertex.getSuccessorVertexNames();
72
+
73
+ return successorVertexNames;
74
+ }
75
+
76
+ getEdgesByTargetVertexName(targetVertexName) {
77
+ const edges = [],
78
+ targetVertex = this.getVertexByVertexName(targetVertexName);
79
+
80
+ if (targetVertex !== null) {
81
+ const immediatePredecessorVertexNames = targetVertex.getImmediatePredecessorVertexNames(),
82
+ sourceVertexNames = immediatePredecessorVertexNames; ///
83
+
84
+ sourceVertexNames.forEach((sourceVertexName) => {
85
+ const edge = Edge.fromSourceVertexNameAndTargetVertexName(sourceVertexName, targetVertexName);
86
+
87
+ edges.push(edge);
88
+ });
89
+ }
90
+
91
+ return edges;
92
+ }
93
+
94
+ getEdgesBySourceVertexName(sourceVertexName) {
95
+ const edges = [],
96
+ sourceVertex = this.getVertexByVertexName(sourceVertexName);
97
+
98
+ if (sourceVertex !== null) {
99
+ const immediateSuccessorVertexNames = sourceVertex.getImmediateSuccessorVertexNames(),
100
+ targetVertexNames = immediateSuccessorVertexNames; ///
101
+
102
+ targetVertexNames.forEach((targetVertexName) => {
103
+ const edge = Edge.fromSourceVertexNameAndTargetVertexName(sourceVertexName, targetVertexName);
104
+
105
+ edges.push(edge);
106
+ });
107
+ }
108
+
109
+ return edges;
110
+ }
111
+
112
+ setVertexByVertexName(vertexName, vertex) {
113
+ this.vertexMap[vertexName] = vertex;
114
+ }
115
+
116
+ deleteVertexByVertexName(vertexName) {
117
+ delete this.vertexMap[vertexName];
118
+ }
119
+
120
+ isEdgePresent(edge) {
121
+ const sourceVertexName = edge.getSourceVertexName(),
122
+ targetVertexName = edge.getTargetVertexName(),
123
+ edgePresent = this.isEdgePresentByVertexNames(sourceVertexName, targetVertexName);
124
+
125
+ return edgePresent;
126
+ }
127
+
128
+ isEdgePresentByVertexNames(sourceVertexName, targetVertexName) {
129
+ let edgePresent = false;
130
+
131
+ const sourceVertex = this.getVertexByVertexName(sourceVertexName),
132
+ targetVertex = this.getVertexByVertexName(targetVertexName),
133
+ sourceVertexAndTargetVertexPresent = (sourceVertex !== null) && (targetVertex !== null);
134
+
135
+ if (sourceVertexAndTargetVertexPresent) {
136
+ edgePresent = sourceVertex.isEdgePresentByTargetVertex(targetVertex);
137
+ }
138
+
139
+ return edgePresent;
140
+ }
141
+
142
+ isVertexPresentByVertexName(vertexName) {
143
+ const vertexNames = this.getVertexNames(),
144
+ vertexNamesIncludesVertexName = vertexNames.includes(vertexName),
145
+ vertexPresent = vertexNamesIncludesVertexName; ///
146
+
147
+ return vertexPresent;
148
+ }
149
+
150
+ getOrderedVertexNames() {
151
+ const vertices = this.getVertices();
152
+
153
+ orderVertices(vertices);
154
+
155
+ const orderedVertices = vertices, ///
156
+ orderedVertexNames = vertexNamesFromVertices(orderedVertices);
157
+
158
+ return orderedVertexNames;
159
+ }
160
+
161
+ addEdge(edge) {
162
+ const sourceVertexName = edge.getSourceVertexName(),
163
+ targetVertexName = edge.getTargetVertexName(),
164
+ success = this.addEdgeByVertexNames(sourceVertexName, targetVertexName);
165
+
166
+ return success;
167
+ }
168
+
169
+ removeEdge(edge) {
170
+ const sourceVertexName = edge.getSourceVertexName(),
171
+ targetVertexName = edge.getTargetVertexName();
172
+
173
+ this.removeEdgeByVertexNames(sourceVertexName, targetVertexName);
174
+ }
175
+
176
+ addEdgeByVertexNames(sourceVertexName, targetVertexName) {
177
+ let success = false;
178
+
179
+ if (sourceVertexName !== targetVertexName) {
180
+ const sourceVertex = this.addVertexByVertexName(sourceVertexName),
181
+ targetVertex = this.addVertexByVertexName(targetVertexName),
182
+ edgePresent = sourceVertex.isEdgePresentByTargetVertex(targetVertex);
183
+
184
+ if (edgePresent) {
185
+ success = true;
186
+ } else {
187
+ const sourceVertexIndex = sourceVertex.getIndex(),
188
+ targetVertexIndex = targetVertex.getIndex(),
189
+ invalidatingEdge = (sourceVertexIndex > targetVertexIndex);
190
+
191
+ success = invalidatingEdge ?
192
+ addInvalidatingEdgeByVertices(sourceVertex, targetVertex) :
193
+ true;
194
+
195
+ if (success) {
196
+ const immediatePredecessorVertex = sourceVertex, ///
197
+ immediateSuccessorVertex = targetVertex; ///
198
+
199
+ immediatePredecessorVertex.addImmediateSuccessorVertex(immediateSuccessorVertex);
200
+
201
+ immediateSuccessorVertex.addImmediatePredecessorVertex(immediatePredecessorVertex);
202
+ }
203
+ }
204
+ }
205
+
206
+ return success;
207
+ }
208
+
209
+ removeEdgeByVertexNames(sourceVertexName, targetVertexName) {
210
+ const edgePresent = this.isEdgePresentByVertexNames(sourceVertexName, targetVertexName);
211
+
212
+ if (edgePresent) {
213
+ const sourceVertex = this.getVertexByVertexName(sourceVertexName),
214
+ targetVertex = this.getVertexByVertexName(targetVertexName);
215
+
216
+ sourceVertex.removeImmediateSuccessorVertex(targetVertex);
217
+ targetVertex.removeImmediatePredecessorVertex(sourceVertex);
218
+ }
219
+ }
220
+
221
+ removeEdgesBySourceVertexName(sourceVertexName) {
222
+ const sourceVertexPresent = this.isVertexPresentByVertexName(sourceVertexName);
223
+
224
+ if (sourceVertexPresent) {
225
+ const sourceVertex = this.getVertexByVertexName(sourceVertexName);
226
+
227
+ sourceVertex.removeOutgoingEdges();
228
+ }
229
+ }
230
+
231
+ removeEdgesByTargetVertexName(targetVertexName) {
232
+ const targetVertexPresent = this.isVertexPresentByVertexName(targetVertexName);
233
+
234
+ if (targetVertexPresent) {
235
+ const targetVertex = this.getVertexByVertexName(targetVertexName);
236
+
237
+ targetVertex.removeIncomingEdges();
238
+ }
239
+ }
240
+
241
+ addVertexByVertexName(vertexName) {
242
+ const vertexPresent = this.isVertexPresentByVertexName(vertexName);
243
+
244
+ if (!vertexPresent) {
245
+ const vertexNames = this.getVertexNames(),
246
+ vertexNamesLength = vertexNames.length,
247
+ name = vertexName, ///
248
+ index = vertexNamesLength, ///
249
+ vertex = Vertex.fromNameAndIndex(name, index);
250
+
251
+ this.setVertexByVertexName(vertexName, vertex);
252
+ }
253
+
254
+ const vertex = this.getVertexByVertexName(vertexName);
255
+
256
+ return vertex;
257
+ }
258
+
259
+ removeVertexByVertexName(vertexName) {
260
+ let removedEdges = null;
261
+
262
+ const vertexPresent = this.isVertexPresentByVertexName(vertexName);
263
+
264
+ if (vertexPresent) {
265
+ removedEdges = [];
266
+
267
+ const vertex = this.getVertexByVertexName(vertexName);
268
+
269
+ vertex.forEachImmediateSuccessorVertex((immediateSuccessVertex) => {
270
+ const immediatePredecessorVertex = vertex, ///
271
+ immediatePredecessorVertexName = immediatePredecessorVertex.getName(),
272
+ immediateSuccessVertexName = immediateSuccessVertex.getName(),
273
+ removedEdgeSourceVertexName = immediatePredecessorVertexName, ///
274
+ removedEdgeTargetVertexName = immediateSuccessVertexName, ///
275
+ removedEdge = new Edge(removedEdgeSourceVertexName, removedEdgeTargetVertexName);
276
+
277
+ removedEdges.push(removedEdge);
278
+
279
+ immediateSuccessVertex.removeImmediatePredecessorVertex(immediatePredecessorVertex);
280
+ });
281
+
282
+ vertex.forEachImmediatePredecessorVertex((immediatePredecessorVertex) => {
283
+ const immediateSuccessVertex = vertex, ///
284
+ immediatePredecessorVertexName = immediatePredecessorVertex.getName(),
285
+ immediateSuccessVertexName = immediateSuccessVertex.getName(), ///
286
+ removedEdgeSourceVertexName = immediatePredecessorVertexName, ///
287
+ removedEdgeTargetVertexName = immediateSuccessVertexName, ///
288
+ removedEdge = new Edge(removedEdgeSourceVertexName, removedEdgeTargetVertexName);
289
+
290
+ removedEdges.push(removedEdge);
291
+
292
+ immediatePredecessorVertex.removeImmediateSuccessorVertex(immediateSuccessVertex);
293
+ });
294
+
295
+ this.deleteVertexByVertexName(vertexName);
296
+
297
+ const deletedVertex = vertex, ///
298
+ deletedVertexIndex = deletedVertex.getIndex(),
299
+ vertices = this.getVertices(),
300
+ affectedVertices = vertices.reduce((affectedVertices, vertex) => {
301
+ const vertexIndex = vertex.getIndex(),
302
+ vertexAffected = (vertexIndex > deletedVertexIndex);
303
+
304
+ if (vertexAffected) {
305
+ const affectedVertex = vertex; ///
306
+
307
+ affectedVertices.push(affectedVertex);
308
+ }
309
+
310
+ return affectedVertices;
311
+ }, []);
312
+
313
+ affectedVertices.forEach((affectedVertex) => affectedVertex.decrementIndex());
314
+ }
315
+
316
+ return removedEdges;
317
+ }
318
+
319
+ static fromNothing() {
320
+ const vertexMap = {},
321
+ directedAcyclicGraph = new DirectedAcyclicGraph(vertexMap);
322
+
323
+ return directedAcyclicGraph;
324
+ }
325
+
326
+ static fromVertexNames(vertexNames) {
327
+ const vertexMap = vertexMapFromVertexNames(vertexNames);
328
+
329
+ const directedAcyclicGraph = new DirectedAcyclicGraph(vertexMap);
330
+
331
+ return directedAcyclicGraph;
332
+ }
333
+
334
+ static fromOrderedVertices(orderedVertices) {
335
+ const vertexMap = vertexMapFromOrderedVertices(orderedVertices);
336
+
337
+ addEdgesToVertices(orderedVertices, vertexMap);
338
+
339
+ const directedAcyclicGraph = new DirectedAcyclicGraph(vertexMap);
340
+
341
+ return directedAcyclicGraph;
342
+ }
343
+ }
344
+
345
+ function addInvalidatingEdgeByVertices(sourceVertex, targetVertex) {
346
+ let success = false;
347
+
348
+ const forwardsAffectedVertices = targetVertex.retrieveForwardsAffectedVertices(sourceVertex),
349
+ lastForwardsAffectedVertex = last(forwardsAffectedVertices),
350
+ resultsInCycle = (lastForwardsAffectedVertex === sourceVertex);
351
+
352
+ if (!resultsInCycle) {
353
+ const backwardsAffectedVertices = sourceVertex.retrieveBackwardsAffectedVertices();
354
+
355
+ orderVertices(backwardsAffectedVertices);
356
+
357
+ orderVertices(forwardsAffectedVertices);
358
+
359
+ const affectedVertices = [].concat(backwardsAffectedVertices).concat(forwardsAffectedVertices),
360
+ affectedVertexIndices = affectedVertices.map((affectedVertex) => {
361
+ const affectedVertexIndex = affectedVertex.getIndex();
362
+
363
+ return affectedVertexIndex;
364
+ });
365
+
366
+ affectedVertexIndices.sort((indexA, indexB) => (indexA - indexB));
367
+
368
+ affectedVertices.forEach((affectedVertex, index) => {
369
+ const affectedVertexIndex = affectedVertexIndices[index];
370
+
371
+ affectedVertex.setIndex(affectedVertexIndex);
372
+ });
373
+
374
+ success = true;
375
+ }
376
+
377
+ return success;
378
+ }
379
+
380
+ function vertexMapFromVertexNames(vertexNames) {
381
+ const vertexMap = {};
382
+
383
+ vertexNames.forEach((vertexName, index) => {
384
+ const name = vertexName, ///
385
+ vertex = Vertex.fromNameAndIndex(name, index);
386
+
387
+ vertexMap[vertexName] = vertex;
388
+ });
389
+
390
+ return vertexMap;
391
+ }
392
+
393
+ function vertexMapFromOrderedVertices(orderedVertices) {
394
+ const vertexMap = {};
395
+
396
+ orderedVertices.forEach((orderedVertex, index) => {
397
+ const name = orderedVertex.getName(),
398
+ vertex = Vertex.fromNameAndIndex(name, index),
399
+ vertexName = name; ///
400
+
401
+ vertexMap[vertexName] = vertex;
402
+ });
403
+
404
+ return vertexMap;
405
+ }
406
+
407
+ function addEdgesToVertices(orderedVertices, vertexMap) {
408
+ orderedVertices.forEach((orderedVertex) => {
409
+ orderedVertex.forEachOutgoingEdge((outgoingEdge) => {
410
+ const sourceVertexName = outgoingEdge.getSourceVertexName(),
411
+ targetVertexName = outgoingEdge.getTargetVertexName(),
412
+ immediatePredecessorVertexName = sourceVertexName, ///
413
+ immediateSuccessorVertexName = targetVertexName,
414
+ immediatePredecessorVertex = vertexMap[immediatePredecessorVertexName], ///
415
+ immediateSuccessorVertex = vertexMap[immediateSuccessorVertexName]; ///
416
+
417
+ immediatePredecessorVertex.addImmediateSuccessorVertex(immediateSuccessorVertex);
418
+
419
+ immediateSuccessorVertex.addImmediatePredecessorVertex(immediatePredecessorVertex);
420
+ });
421
+ });
422
+ }
@@ -1,15 +1,14 @@
1
1
  "use strict";
2
2
 
3
- import { Graph } from "occam-kahn";
4
3
  import { arrayUtilities } from "necessary";
5
- import { DirectedAcyclicGraph } from "occam-pearce-kelly";
6
4
 
7
5
  import Edge from "./edge";
8
6
  import Cycle from "./cycle";
9
7
  import PartialCycle from "./partialCycle";
8
+ import DirectedAcyclicGraph from "./directedAcyclicGraph";
10
9
 
11
- import { vertexNamesFromVertexLiterals, forwardsDepthFirstSearch } from "./utilities/vertex";
12
- import { edgesFromVertexLiterals, checkEdgesIncludesEdge, removeEdgeFromEdges, edgesBySourceVertexName, edgesByTargetVertexName } from "./utilities/edge";
10
+ import { forwardsDepthFirstSearch } from "./utilities/vertex";
11
+ import { checkEdgesIncludesEdge, removeEdgeFromEdges, edgesBySourceVertexName, edgesByTargetVertexName } from "./utilities/edge";
13
12
 
14
13
  const { first, filter } = arrayUtilities;
15
14
 
@@ -309,36 +308,4 @@ export default class DirectedGraph {
309
308
 
310
309
  return directedGraph;
311
310
  }
312
-
313
- static fromVertexLiterals(vertexLiterals) {
314
- const vertexNames = vertexNamesFromVertexLiterals(vertexLiterals),
315
- edges = edgesFromVertexLiterals(vertexLiterals),
316
- directedGraph = DirectedGraph.fromVertexNamesAndEdges(vertexNames, edges);
317
-
318
- return directedGraph;
319
- }
320
-
321
- static fromVertexNamesAndEdges(vertexNames, edges) {
322
- let directedGraph;
323
-
324
- const graph = Graph.fromVertexNamesAndEdges(vertexNames, edges),
325
- cyclesPresent = graph.areCyclesPresent();
326
-
327
- if (cyclesPresent) {
328
- const cyclicEdges = [],
329
- directedAcyclicGraph = DirectedAcyclicGraph.fromVertexNames(vertexNames);
330
-
331
- directedGraph = new DirectedGraph(cyclicEdges, directedAcyclicGraph);
332
-
333
- edges.forEach((edge) => directedGraph.addEdge(edge));
334
- } else {
335
- const orderedVertices = graph.getOrderedVertices(),
336
- cyclicEdges = [],
337
- directedAcyclicGraph = DirectedAcyclicGraph.fromOrderedVertices(orderedVertices);
338
-
339
- directedGraph = new DirectedGraph(cyclicEdges, directedAcyclicGraph);
340
- }
341
-
342
- return directedGraph;
343
- }
344
311
  }
package/src/edge.js CHANGED
@@ -1,5 +1,54 @@
1
1
  "use strict";
2
2
 
3
- import { Edge } from "occam-pearce-kelly";
3
+ export default class Edge {
4
+ constructor(sourceVertexName, targetVertexName) {
5
+ this.sourceVertexName = sourceVertexName;
6
+ this.targetVertexName = targetVertexName;
7
+ }
8
+
9
+ getSourceVertexName() {
10
+ return this.sourceVertexName;
11
+ }
12
+
13
+ getTargetVertexName() {
14
+ return this.targetVertexName;
15
+ }
16
+
17
+ match(edge) {
18
+ const sourceVertexName = edge.getSourceVertexName(),
19
+ targetVertexName = edge.getTargetVertexName(),
20
+ matches = ((this.sourceVertexName === sourceVertexName) && (this.targetVertexName === targetVertexName));
21
+
22
+ return matches;
23
+ }
4
24
 
5
- export default Edge;
25
+ matchVertexName(vertexName) {
26
+ const matches = ((this.sourceVertexName === vertexName) || (this.targetVertexName === vertexName));
27
+
28
+ return matches;
29
+ }
30
+
31
+ matchSourceVertexName(sourceVertexName) {
32
+ const matches = (this.sourceVertexName === sourceVertexName);
33
+
34
+ return matches;
35
+ }
36
+
37
+ matchTargetVertexName(targetVertexName) {
38
+ const matches = (this.targetVertexName === targetVertexName);
39
+
40
+ return matches;
41
+ }
42
+
43
+ matchVertexNames(sourceVertexName, targetVertexName) {
44
+ const matches = ((this.sourceVertexName === sourceVertexName) && (this.targetVertexName === targetVertexName));
45
+
46
+ return matches;
47
+ }
48
+
49
+ static fromSourceVertexNameAndTargetVertexName(sourceVertexName, targetVertexName) {
50
+ const edge = new Edge(sourceVertexName, targetVertexName);
51
+
52
+ return edge;
53
+ }
54
+ }
@@ -6,27 +6,6 @@ const { prune } = arrayUtilities;
6
6
 
7
7
  const remove = prune; ///
8
8
 
9
- export function edgesFromVertexLiterals(vertexLiterals) {
10
- const edges = [];
11
-
12
- vertexLiterals.forEach((vertexLiteral) => {
13
- const firstVertexLiteralElement = first(vertexLiteral),
14
- secondVertexLiteralElement = second(vertexLiteral),
15
- ancestorVertexNames = secondVertexLiteralElement, ///
16
- vertexName = firstVertexLiteralElement; ///
17
-
18
- ancestorVertexNames.forEach((ancestorVertexName) => {
19
- const sourceVertexName = ancestorVertexName, ///
20
- targetVertexName = vertexName, ///
21
- edge = new Edge(sourceVertexName, targetVertexName);
22
-
23
- edges.push(edge);
24
- });
25
- });
26
-
27
- return edges;
28
- }
29
-
30
9
  export function checkEdgesIncludesEdge(edge, edges) {
31
10
  const edge1 = edge, ///
32
11
  edgesIncludesEdge = edges.some((edge) => {
@@ -1,37 +1,22 @@
1
1
  "use strict";
2
2
 
3
- import { arrayUtilities } from "necessary";
4
-
5
- const { first, second } = arrayUtilities;
6
-
7
- export function vertexNamesFromVertexLiterals(vertexLiterals) {
8
- const vertexNameMap = {};
9
-
10
- vertexLiterals.forEach((vertexLiteral) => {
11
- const firstVertexLiteralElement = first(vertexLiteral),
12
- vertexName = firstVertexLiteralElement, ///
13
- vertexExists = vertexNameMap.hasOwnProperty(vertexName);
14
-
15
- if (!vertexExists) {
16
- vertexNameMap[vertexName] = vertexName;
3
+ export function orderVertices(vertices) { ///
4
+ vertices.sort((firstVertex, secondVertex) => {
5
+ const firstVertexIndex = firstVertex.getIndex(),
6
+ secondVertexIndex = secondVertex.getIndex();
7
+
8
+ if (false) {
9
+ ///
10
+ } else if (firstVertexIndex < secondVertexIndex) {
11
+ return -1;
12
+ } else if (firstVertexIndex > secondVertexIndex) {
13
+ return +1;
17
14
  }
18
-
19
- const secondVertexLiteralElement = second(vertexLiteral),
20
- ancestorVertexNames = secondVertexLiteralElement; ///
21
-
22
- ancestorVertexNames.forEach((ancestorVertexName) => {
23
- const ancestorVertexExists = vertexNameMap.hasOwnProperty(ancestorVertexName);
24
-
25
- if (!ancestorVertexExists) {
26
- vertexNameMap[ancestorVertexName] = ancestorVertexName;
27
- }
28
- });
29
15
  });
30
16
 
31
- const vertexNameMapKeys = Object.keys(vertexNameMap),
32
- vertexNames = vertexNameMapKeys; ///
17
+ const orderedVertices = vertices; ///
33
18
 
34
- return vertexNames;
19
+ return orderedVertices;
35
20
  }
36
21
 
37
22
  export function vertexNamesFromVertices(vertices) {