1 // Copyright 2005 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS-IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Original author: ericv@google.com (Eric Veach)
16 // Converted to D:  madric@gmail.com (Vijay Nayar)
17 
18 module s2.s2coords;
19 
20 // This file contains documentation of the various coordinate systems used
21 // throughout the library.  Most importantly, S2 defines a framework for
22 // decomposing the unit sphere into a hierarchy of "cells".  Each cell is a
23 // quadrilateral bounded by four geodesics.  The top level of the hierarchy is
24 // obtained by projecting the six faces of a cube onto the unit sphere, and
25 // lower levels are obtained by subdividing each cell into four children
26 // recursively.  Cells are numbered such that sequentially increasing cells
27 // follow a continuous space-filling curve over the entire sphere.  The
28 // transformation is designed to make the cells at each level fairly uniform
29 // in size.
30 //
31 //
32 ////////////////////////// S2Cell Decomposition /////////////////////////
33 //
34 // The following methods define the cube-to-sphere projection used by
35 // the S2Cell decomposition.
36 //
37 // In the process of converting a latitude-longitude pair to a 64-bit cell
38 // id, the following coordinate systems are used:
39 //
40 //  (id)
41 //    An S2CellId is a 64-bit encoding of a face and a Hilbert curve position
42 //    on that face.  The Hilbert curve position implicitly encodes both the
43 //    position of a cell and its subdivision level (see s2cell_id.h).
44 //
45 //  (face, i, j)
46 //    Leaf-cell coordinates.  "i" and "j" are integers in the range
47 //    [0,(2**30)-1] that identify a particular leaf cell on the given face.
48 //    The (i, j) coordinate system is right-handed on each face, and the
49 //    faces are oriented such that Hilbert curves connect continuously from
50 //    one face to the next.
51 //
52 //  (face, s, t)
53 //    Cell-space coordinates.  "s" and "t" are real numbers in the range
54 //    [0,1] that identify a point on the given face.  For example, the point
55 //    (s, t) = (0.5, 0.5) corresponds to the center of the top-level face
56 //    cell.  This point is also a vertex of exactly four cells at each
57 //    subdivision level greater than zero.
58 //
59 //  (face, si, ti)
60 //    Discrete cell-space coordinates.  These are obtained by multiplying
61 //    "s" and "t" by 2**31 and rounding to the nearest unsigned integer.
62 //    Discrete coordinates lie in the range [0,2**31].  This coordinate
63 //    system can represent the edge and center positions of all cells with
64 //    no loss of precision (including non-leaf cells).  In binary, each
65 //    coordinate of a level-k cell center ends with a 1 followed by
66 //    (30 - k) 0s.  The coordinates of its edges end with (at least)
67 //    (31 - k) 0s.
68 //
69 //  (face, u, v)
70 //    Cube-space coordinates in the range [-1,1].  To make the cells at each
71 //    level more uniform in size after they are projected onto the sphere,
72 //    we apply a nonlinear transformation of the form u=f(s), v=f(t).
73 //    The (u, v) coordinates after this transformation give the actual
74 //    coordinates on the cube face (modulo some 90 degree rotations) before
75 //    it is projected onto the unit sphere.
76 //
77 //  (face, u, v, w)
78 //    Per-face coordinate frame.  This is an extension of the (face, u, v)
79 //    cube-space coordinates that adds a third axis "w" in the direction of
80 //    the face normal.  It is always a right-handed 3D coordinate system.
81 //    Cube-space coordinates can be converted to this frame by setting w=1,
82 //    while (u,v,w) coordinates can be projected onto the cube face by
83 //    dividing by w, i.e. (face, u/w, v/w).
84 //
85 //  (x, y, z)
86 //    Direction vector (S2Point).  Direction vectors are not necessarily unit
87 //    length, and are often chosen to be points on the biunit cube
88 //    [-1,+1]x[-1,+1]x[-1,+1].  They can be be normalized to obtain the
89 //    corresponding point on the unit sphere.
90 //
91 //  (lat, lng)
92 //    Latitude and longitude (S2LatLng).  Latitudes must be between -90 and
93 //    90 degrees inclusive, and longitudes must be between -180 and 180
94 //    degrees inclusive.
95 //
96 // Note that the (i, j), (s, t), (si, ti), and (u, v) coordinate systems are
97 // right-handed on all six faces.
98 
99 import s2.r2point;
100 import s2.s2point;
101 import s2.util.math.mathutil;
102 import bitop = core.bitop;
103 import algorithm = std.algorithm;
104 import math = std.math;
105 
106 // This is the number of levels needed to specify a leaf cell.  This
107 // constant is defined here so that the S2::Metric class and the conversion
108 // functions below can be implemented without including s2cell_id.h.  Please
109 // see s2cell_id.h for other useful constants and conversion functions.
110 immutable int MAX_CELL_LEVEL = 30;
111 
112 // The maximum index of a valid leaf cell plus one.  The range of valid leaf
113 // cell indices is [0..kLimitIJ-1].
114 immutable int LIMIT_IJ = 1 << MAX_CELL_LEVEL;  // == S2CellId::kMaxSize
115 
116 // The maximum value of an si- or ti-coordinate.  The range of valid (si,ti)
117 // values is [0..MAX_SI_TI].
118 immutable uint MAX_SI_TI = 1U << (MAX_CELL_LEVEL + 1);
119 
120 // Convert the i- or j-index of a leaf cell to the minimum corresponding s-
121 // or t-value contained by that cell.  The argument must be in the range
122 // [0..2**30], i.e. up to one position beyond the normal range of valid leaf
123 // cell indices.
124 double IJtoSTMin(int i)
125 in {
126   assert(i >= 0 && i <= LIMIT_IJ);
127 } do {
128   return (1.0 / LIMIT_IJ) * i;
129 }
130 
131 // Return the i- or j-index of the leaf cell containing the given
132 // s- or t-value.  If the argument is outside the range spanned by valid
133 // leaf cell indices, return the index of the closest valid leaf cell (i.e.,
134 // return values are clamped to the range of valid leaf cell indices).
135 int STtoIJ(double s) {
136   return algorithm.max(
137       0, algorithm.min(LIMIT_IJ - 1, cast(int) math.lround(LIMIT_IJ * s - 0.5)));
138 }
139 
140 // Convert an si- or ti-value to the corresponding s- or t-value.
141 double SiTitoST(uint si)
142 in {
143   assert(si >= 0 && si <= MAX_SI_TI);
144 } do {
145   return (1.0 / MAX_SI_TI) * si;
146 }
147 
148 // Return the si- or ti-coordinate that is nearest to the given s- or
149 // t-value.  The result may be outside the range of valid (si,ti)-values.
150 uint STtoSiTi(double s) {
151   // MAX_SI_TI == 2^31, so the result doesn't fit in an int32 when s == 1.
152   return cast(uint) math.lround(s * MAX_SI_TI);
153 }
154 
155 // Convert (face, u, v) coordinates to a direction vector (not
156 // necessarily unit length).
157 S2Point FaceUVtoXYZ(int face, double u, double v) {
158   switch (face) {
159     case 0:  return S2Point([ 1,  u,  v]);
160     case 1:  return S2Point([-u,  1,  v]);
161     case 2:  return S2Point([-u, -v,  1]);
162     case 3:  return S2Point([-1, -v, -u]);
163     case 4:  return S2Point([ v, -1, -u]);
164     default: return S2Point([ v,  u, -1]);
165   }
166 }
167 
168 S2Point FaceUVtoXYZ(int face, in R2Point uv) {
169   return FaceUVtoXYZ(face, uv.x, uv.y);
170 }
171 
172 // If the dot product of p with the given face normal is positive,
173 // set the corresponding u and v values (which may lie outside the range
174 // [-1,1]) and return true.  Otherwise return false.
175 bool FaceXYZtoUV(int face, in S2Point p, out double pu, out double pv) {
176   if (face < 3) {
177     if (p[face] <= 0) return false;
178   } else {
179     if (p[face-3] >= 0) return false;
180   }
181   ValidFaceXYZtoUV(face, p, pu, pv);
182   return true;
183 }
184 
185 
186 bool FaceXYZtoUV(int face, in S2Point p, out R2Point puv) {
187   return FaceXYZtoUV(face, p, puv.data[0], puv.data[1]);
188 }
189 
190 // Given a *valid* face for the given point p (meaning that dot product
191 // of p with the face normal is positive), return the corresponding
192 // u and v values (which may lie outside the range [-1,1]).
193 void ValidFaceXYZtoUV(int face, in S2Point p, out double pu, out double pv)
194 in {
195   assert(p.dotProd(GetNorm(face)) > 0);
196 } do {
197   switch (face) {
198     case 0:  pu =  p[1] / p[0]; pv =  p[2] / p[0]; break;
199     case 1:  pu = -p[0] / p[1]; pv =  p[2] / p[1]; break;
200     case 2:  pu = -p[0] / p[2]; pv = -p[1] / p[2]; break;
201     case 3:  pu =  p[2] / p[0]; pv =  p[1] / p[0]; break;
202     case 4:  pu =  p[2] / p[1]; pv = -p[0] / p[1]; break;
203     default: pu = -p[1] / p[2]; pv = -p[0] / p[2]; break;
204   }
205 }
206 
207 void ValidFaceXYZtoUV(int face, in S2Point p, out R2Point puv) {
208   ValidFaceXYZtoUV(face, p, puv.data[0], puv.data[1]);
209 }
210 
211 // Transform the given point P to the (u,v,w) coordinate frame of the given
212 // face (where the w-axis represents the face normal).
213 S2Point FaceXYZtoUVW(int face, in S2Point p) {
214   // The result coordinates are simply the dot products of P with the (u,v,w)
215   // axes for the given face (see kFaceUVWAxes).
216   switch (face) {
217     case 0:  return S2Point([ p.y(),  p.z(),  p.x()]);
218     case 1:  return S2Point([-p.x(),  p.z(),  p.y()]);
219     case 2:  return S2Point([-p.x(), -p.y(),  p.z()]);
220     case 3:  return S2Point([-p.z(), -p.y(), -p.x()]);
221     case 4:  return S2Point([-p.z(),  p.x(), -p.y()]);
222     default: return S2Point([ p.y(),  p.x(), -p.z()]);
223   }
224 }
225 
226 /**
227  * Return the face containing the given direction vector.  (For points on
228  * the boundary between faces, the result is arbitrary but repeatable.)
229  */
230 int GetFace(in S2Point p) {
231   int face = p.largestAbsComponent();
232   if (p[face] < 0) {
233     face += 3;
234   }
235   return face;
236 }
237 
238 /**
239  * Convert a direction vector (not necessarily unit length) to
240  * (face, u, v) coordinates.
241  */
242 int XYZtoFaceUV(in S2Point p, out double pu, out double pv) {
243   int face = GetFace(p);
244   ValidFaceXYZtoUV(face, p, pu, pv);
245   return face;
246 }
247 
248 int XYZtoFaceUV(in S2Point p, out R2Point puv) {
249   return XYZtoFaceUV(p, puv.data[0], puv.data[1]);
250 }
251 
252 /**
253  * Convert a direction vector (not necessarily unit length) to
254  * (face, si, ti) coordinates and, if p is exactly equal to the center of a
255  * cell, return the level of this cell (-1 otherwise).
256  */
257 int XYZtoFaceSiTi(in S2Point p, out int face, out uint si, out uint ti) {
258   double u, v;
259 
260   face = XYZtoFaceUV(p, u, v);
261   si = STtoSiTi(UVtoST(u));
262   ti = STtoSiTi(UVtoST(v));
263   // If the levels corresponding to si,ti are not equal, then p is not a cell
264   // center.  The si,ti values 0 and kMaxSiTi need to be handled specially
265   // because they do not correspond to cell centers at any valid level; they
266   // are mapped to level -1 by the code below.
267   int level = MAX_CELL_LEVEL - bitop.bsf(si | MAX_SI_TI);
268   if (level < 0 ||
269       level != MAX_CELL_LEVEL - bitop.bsf(ti | MAX_SI_TI)) {
270     return -1;
271   }
272   assert(level <= MAX_CELL_LEVEL);
273   // In infinite precision, this test could be changed to ST == SiTi. However,
274   // due to rounding errors, UVtoST(XYZtoFaceUV(FaceUVtoXYZ(STtoUV(...)))) is
275   // not idempotent. On the other hand, center_raw is computed exactly the same
276   // way p was originally computed (if it is indeed the center of an S2Cell):
277   // the comparison can be exact.
278   S2Point center = FaceSiTitoXYZ(face, si, ti).normalize();
279   return p == center ? level : -1;
280 }
281 
282 // Convert (face, si, ti) coordinates to a direction vector (not necessarily
283 // unit length).
284 S2Point FaceSiTitoXYZ(int face, uint si, uint ti) {
285   double u = STtoUV(SiTitoST(si));
286   double v = STtoUV(SiTitoST(ti));
287   return FaceUVtoXYZ(face, u, v);
288 }
289 
290 // Return the right-handed normal (not necessarily unit length) for an
291 // edge in the direction of the positive v-axis at the given u-value on
292 // the given face.  (This vector is perpendicular to the plane through
293 // the sphere origin that contains the given edge.)
294 S2Point GetUNorm(int face, double u) {
295   switch (face) {
296     case 0:  return S2Point([ u, -1,  0]);
297     case 1:  return S2Point([ 1,  u,  0]);
298     case 2:  return S2Point([ 1,  0,  u]);
299     case 3:  return S2Point([-u,  0,  1]);
300     case 4:  return S2Point([ 0, -u,  1]);
301     default: return S2Point([ 0, -1, -u]);
302   }
303 }
304 
305 
306 // Return the right-handed normal (not necessarily unit length) for an
307 // edge in the direction of the positive u-axis at the given v-value on
308 // the given face.
309 S2Point GetVNorm(int face, double v) {
310   switch (face) {
311     case 0:  return S2Point([-v,  0,  1]);
312     case 1:  return S2Point([ 0, -v,  1]);
313     case 2:  return S2Point([ 0, -1, -v]);
314     case 3:  return S2Point([ v, -1,  0]);
315     case 4:  return S2Point([ 1,  v,  0]);
316     default: return S2Point([ 1,  0,  v]);
317   }
318 }
319 
320 // Return the unit-length normal, u-axis, or v-axis for the given face.
321 S2Point GetNorm(int face) {
322   return GetUVWAxis(face, 2);
323 }
324 
325 S2Point GetUAxis(int face) {
326   return GetUVWAxis(face, 0);
327 }
328 
329 S2Point GetVAxis(int face) {
330   return GetUVWAxis(face, 1);
331 }
332 
333 // Return the given axis of the given face (u=0, v=1, w=2).
334 S2Point GetUVWAxis(int face, int axis) {
335   double[3] p = FACE_UVW_AXES[face][axis];
336   return S2Point([p[0], p[1], p[2]]);
337 }
338 
339 // With respect to the (u,v,w) coordinate system of a given face, return the
340 // face that lies in the given direction (negative=0, positive=1) of the
341 // given axis (u=0, v=1, w=2).  For example, GetUVWFace(4, 0, 1) returns the
342 // face that is adjacent to face 4 in the positive u-axis direction.
343 int GetUVWFace(int face, int axis, int direction)
344 in {
345   assert(face >= 0 && face <= 5);
346   assert(axis >= 0 && axis <= 2);
347   assert(direction >= 0 && direction <= 1);
348 } do {
349   return FACE_UVW_FACES[face][axis][direction];
350 }
351 
352 
353 //////////////////   Implementation details follow   ////////////////////
354 
355 
356 // We have implemented three different projections from cell-space (s,t) to
357 // cube-space (u,v): linear, quadratic, and tangent.  They have the following
358 // tradeoffs:
359 //
360 //   Linear - This is the fastest transformation, but also produces the least
361 //   uniform cell sizes.  Cell areas vary by a factor of about 5.2, with the
362 //   largest cells at the center of each face and the smallest cells in
363 //   the corners.
364 //
365 //   Tangent - Transforming the coordinates via atan() makes the cell sizes
366 //   more uniform.  The areas vary by a maximum ratio of 1.4 as opposed to a
367 //   maximum ratio of 5.2.  However, each call to atan() is about as expensive
368 //   as all of the other calculations combined when converting from points to
369 //   cell ids, i.e. it reduces performance by a factor of 3.
370 //
371 //   Quadratic - This is an approximation of the tangent projection that
372 //   is much faster and produces cells that are almost as uniform in size.
373 //   It is about 3 times faster than the tangent projection for converting
374 //   cell ids to points or vice versa.  Cell areas vary by a maximum ratio of
375 //   about 2.1.
376 //
377 // Here is a table comparing the cell uniformity using each projection.  "Area
378 // ratio" is the maximum ratio over all subdivision levels of the largest cell
379 // area to the smallest cell area at that level, "edge ratio" is the maximum
380 // ratio of the longest edge of any cell to the shortest edge of any cell at
381 // the same level, and "diag ratio" is the ratio of the longest diagonal of
382 // any cell to the shortest diagonal of any cell at the same level.  "ToPoint"
383 // and "FromPoint" are the times in microseconds required to convert cell ids
384 // to and from points (unit vectors) respectively.  "ToPointRaw" is the time
385 // to convert to a non-unit-length vector, which is all that is needed for
386 // some purposes.
387 //
388 //               Area    Edge    Diag   ToPointRaw  ToPoint  FromPoint
389 //              Ratio   Ratio   Ratio             (microseconds)
390 // -------------------------------------------------------------------
391 // Linear:      5.200   2.117   2.959      0.020     0.087     0.085
392 // Tangent:     1.414   1.414   1.704      0.237     0.299     0.258
393 // Quadratic:   2.082   1.802   1.932      0.033     0.096     0.108
394 //
395 // The worst-case cell aspect ratios are about the same with all three
396 // projections.  The maximum ratio of the longest edge to the shortest edge
397 // within the same cell is about 1.4 and the maximum ratio of the diagonals
398 // within the same cell is about 1.7.
399 //
400 // This data was produced using s2cell_test and s2cell_id_test.
401 
402 version = S2_QUADRATIC_PROJECTION;
403 
404 version (S2_LINEAR_PROJECTION) {
405   double STtoUV(double s) {
406     return 2 * s - 1;
407   }
408 
409   double UVtoST(double u) {
410     return 0.5 * (u + 1);
411   }
412 }
413 
414 version (S2_TAN_PROJECTION) {
415   double STtoUV(double s) {
416     // Unfortunately, tan(M_PI_4) is slightly less than 1.0.  This isn't due to
417     // a flaw in the implementation of tan(), it's because the derivative of
418     // tan(x) at x=pi/4 is 2, and it happens that the two adjacent floating
419     // point numbers on either side of the infinite-precision value of pi/4 have
420     // tangents that are slightly below and slightly above 1.0 when rounded to
421     // the nearest double-precision result.
422 
423     s = math.tan(math.PI_2 * s - math.PI_4);
424     return s + (1.0 / (1L << 53)) * s;
425   }
426 
427   double UVtoST(double u) {
428     double a = math.atan(u);
429     return (2 * math.M_1_PI) * (a + math.PI_4);
430   }
431 }
432 
433 version (S2_QUADRATIC_PROJECTION) {
434   // Convert an s- or t-value to the corresponding u- or v-value.  This is
435   // a non-linear transformation from [-1,1] to [-1,1] that attempts to
436   // make the cell sizes more uniform.
437   double STtoUV(double s) {
438     if (s >= 0.5) return (1/3.) * (4*s*s - 1);
439     else          return (1/3.) * (1 - 4*(1-s)*(1-s));
440   }
441 
442   // The inverse of the STtoUV transformation.  Note that it is not always
443   // true that UVtoST(STtoUV(x)) == x due to numerical errors.
444   double UVtoST(double u) {
445     if (u >= 0) return 0.5 * math.sqrt(1 + 3*u);
446     else        return 1 - 0.5 * math.sqrt(1 - 3*u);
447   }
448 }
449 
450 /**
451  * The canonical Hilbert traversal order looks like an inverted 'U':
452  * the subcells are visited in the order (0,0), (0,1), (1,1), (1,0).
453  * The following tables encode the traversal order for various
454  * orientations of the Hilbert curve (axes swapped and/or directions
455  * of the axes reversed).
456  */
457 
458 /**
459  * Together these flags define a cell orientation.  If 'kSwapMask'
460  * is true, then canonical traversal order is flipped around the
461  * diagonal (i.e. i and j are swapped with each other).  If
462  * 'kInvertMask' is true, then the traversal order is rotated by 180
463  * degrees (i.e. the bits of i and j are inverted, or equivalently,
464  * the axis directions are reversed).
465  */
466 package immutable int SWAP_MASK = 0x01;
467 package immutable int INVERT_MASK = 0x02;
468 
469 /**
470  * Given a cell orientation and the (i,j)-index of a subcell (0=(0,0),
471  * 1=(0,1), 2=(1,0), 3=(1,1)), return the order in which this subcell is
472  * visited by the Hilbert curve (a position in the range [0..3]).
473  *
474  * IJ_TO_POS[orientation][ij] -> pos
475  */
476 package immutable int[4][4] IJ_TO_POS = [
477   // (0,0) (0,1) (1,0) (1,1)
478   [     0,    1,    3,    2  ],  // canonical order
479   [     0,    3,    1,    2  ],  // axes swapped
480   [     2,    3,    1,    0  ],  // bits inverted
481   [     2,    1,    3,    0  ],  // swapped & inverted
482 ];
483 
484 /**
485  * Return the (i,j) index of the subcell at the given position 'pos' in the
486  * Hilbert curve traversal order with the given orientation.  This is the
487  * inverse of the previous table:
488  *
489  * POS_TO_IJ[orientation][pos] -> ij
490  */
491 package immutable int[4][4] POS_TO_IJ = [
492   // 0  1  2  3
493   [  0, 1, 3, 2 ],    // canonical order:    (0,0), (0,1), (1,1), (1,0)
494   [  0, 2, 3, 1 ],    // axes swapped:       (0,0), (1,0), (1,1), (0,1)
495   [  3, 2, 0, 1 ],    // bits inverted:      (1,1), (1,0), (0,0), (0,1)
496   [  3, 1, 0, 2 ],    // swapped & inverted: (1,1), (0,1), (0,0), (1,0)
497 ];
498 
499 /**
500  * Return a modifier indicating how the orientation of the child subcell
501  * with the given traversal position [0..3] is related to the orientation
502  * of the parent cell.  The modifier should be XOR-ed with the parent
503  * orientation to obtain the curve orientation in the child.
504  *
505  * POS_TO_ORIENTATION[pos] -> orientation_modifier
506  */
507 package immutable int[4] POS_TO_ORIENTATION = [
508   SWAP_MASK,
509   0,
510   0,
511   INVERT_MASK + SWAP_MASK,
512 ];
513 
514 /** The U,V,W axes for each face. */
515 package immutable double[3][3][6] FACE_UVW_AXES = [
516   [
517     [ 0,  1,  0 ],
518     [ 0,  0,  1 ],
519     [ 1,  0,  0 ]
520   ],
521   [
522     [-1,  0,  0 ],
523     [ 0,  0,  1 ],
524     [ 0,  1,  0 ]
525   ],
526   [
527     [-1,  0,  0 ],
528     [ 0, -1,  0 ],
529     [ 0,  0,  1 ]
530   ],
531   [
532     [ 0,  0, -1 ],
533     [ 0, -1,  0 ],
534     [-1,  0,  0 ]
535   ],
536   [
537     [ 0,  0, -1 ],
538     [ 1,  0,  0 ],
539     [ 0, -1,  0 ]
540   ],
541   [
542     [ 0,  1,  0 ],
543     [ 1,  0,  0 ],
544     [ 0,  0, -1 ]
545   ]
546 ];
547 
548 /** The precomputed neighbors of each face (see GetUVWFace). */
549 package immutable int[2][3][6] FACE_UVW_FACES = [
550   [ [ 4, 1 ], [ 5, 2 ], [ 3, 0 ] ],
551   [ [ 0, 3 ], [ 5, 2 ], [ 4, 1 ] ],
552   [ [ 0, 3 ], [ 1, 4 ], [ 5, 2 ] ],
553   [ [ 2, 5 ], [ 1, 4 ], [ 0, 3 ] ],
554   [ [ 2, 5 ], [ 3, 0 ], [ 1, 4 ] ],
555   [ [ 4, 1 ], [ 3, 0 ], [ 2, 5 ] ]
556 ];