Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

Commit f86e69d

Browse files
committed
Merge branch 'master' into wip/arrayslice
2 parents 5b033e5 + a42fc3d commit f86e69d

32 files changed

+273
-89
lines changed

collections/src/main/scala/strawman/collection/ArrayOps.scala

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@ import immutable.ImmutableArray
88
import scala.reflect.ClassTag
99

1010
object ArrayOps {
11-
class WithFilter[A](p: A => Boolean, ao: ArrayOps[A]) extends collection.WithFilter[A, immutable.IndexedSeq] {
12-
protected[this] def filtered = View.Filter(ao.toIterable, p, isFlipped = false)
11+
private[ArrayOps] trait LowPriorityWithFilterOps[A] {
12+
protected def p: A => Boolean
13+
protected def ao: ArrayOps[A]
14+
protected def filtered = View.Filter(ao.toIterable, p, isFlipped = false)
1315
def map[B](f: A => B): immutable.IndexedSeq[B] = ao.iterableFactory.from(View.Map(filtered, f))
1416
def flatMap[B](f: A => IterableOnce[B]): immutable.IndexedSeq[B] = ao.iterableFactory.from(View.FlatMap(filtered, f))
17+
}
18+
19+
class WithFilter[A](protected val p: A => Boolean, protected val ao: ArrayOps[A]) extends collection.WithFilter[A, immutable.IndexedSeq] with LowPriorityWithFilterOps[A] {
1520
def foreach[U](f: A => U): Unit = filtered.foreach(f)
1621
def map[B: ClassTag](f: A => B): Array[B] = ao.fromTaggedIterable(View.Map(filtered, f))
1722
def flatMap[B: ClassTag](f: A => IterableOnce[B]): Array[B] = ao.fromTaggedIterable(View.FlatMap(filtered, f))
@@ -78,6 +83,8 @@ class ArrayOps[A](val xs: Array[A]) extends AnyVal
7883

7984
def zip[B: ClassTag](that: Iterable[B]): Array[(A, B)] = fromTaggedIterable(View.Zip(toIterable, that))
8085

86+
def zipWithIndex(implicit ct: ClassTag[(A, Int)]): Array[(A, Int)] = fromTaggedIterable(View.ZipWithIndex(toIterable))
87+
8188
def appended[B >: A : ClassTag](x: B): Array[B] = fromTaggedIterable(View.Append(toIterable, x))
8289
@`inline` final def :+ [B >: A : ClassTag](x: B): Array[B] = appended(x)
8390
def prepended[B >: A : ClassTag](x: B): Array[B] = fromTaggedIterable(View.Prepend(x, toIterable))
@@ -116,4 +123,23 @@ class ArrayOps[A](val xs: Array[A]) extends AnyVal
116123
}
117124
(a1, a2)
118125
}
126+
127+
def transpose[B](implicit asArray: A => Array[B]): Array[Array[B]] = {
128+
val aClass = xs.getClass.getComponentType
129+
val bb = Array.newBuilder[Array[B]](ClassTag[Array[B]](aClass))
130+
if (isEmpty) bb.result()
131+
else {
132+
def mkRowBuilder() = Array.newBuilder[B](ClassTag[B](aClass.getComponentType))
133+
val bs = asArray(head) map ((x: B) => mkRowBuilder())
134+
for (xs <- this) {
135+
var i = 0
136+
for (x <- asArray(xs)) {
137+
bs(i) += x
138+
i += 1
139+
}
140+
}
141+
for (b <- bs) bb += b.result()
142+
bb.result()
143+
}
144+
}
119145
}

collections/src/main/scala/strawman/collection/DefaultMap.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,4 @@ trait DefaultMap[K, +V] extends Map[K, V] { self =>
3333
// Members declared in MapOps
3434
def mapFactory: MapFactory[Map] = Map
3535
def empty: Map[K,V] = mapFactory.empty
36-
protected[this] def mapFromIterable[K2, V2](it: Iterable[(K2, V2)]): Map[K2,V2] = mapFactory.from(it)
3736
}

collections/src/main/scala/strawman/collection/Iterable.scala

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -386,18 +386,49 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] {
386386
if (knownSize >= 0) copyToArray(new Array[B](knownSize), 0)
387387
else ArrayBuffer.from(this).toArray[B]
388388

389-
/** Copy all elements of this collection to array `xs`, starting at `start`. */
390-
def copyToArray[B >: A](xs: Array[B], start: Int = 0): xs.type = {
391-
var i = start
392-
val it = iterator()
393-
while (it.hasNext) {
394-
xs(i) = it.next()
395-
i += 1
396-
}
397-
xs
398-
}
389+
/** Copy elements of this collection to an array.
390+
* Fills the given array `xs` starting at index `start`.
391+
* Copying will stop once either the all elements of this collection have been copied,
392+
* or the end of the array is reached.
393+
*
394+
* @param xs the array to fill.
395+
* @param start the starting index.
396+
* @tparam B the type of the elements of the array.
397+
*
398+
* @usecase def copyToArray(xs: Array[A], start: Int): Unit
399+
*
400+
* $willNotTerminateInf
401+
*/
402+
def copyToArray[B >: A](xs: Array[B], start: Int = 0): xs.type = iterator().copyToArray(xs, start)
403+
404+
/** Copy elements of this collection to an array.
405+
* Fills the given array `xs` starting at index `start` with at most
406+
* `len` values produced by this iterator.
407+
* Copying will stop once either the all elements of this collection have been copied,
408+
* or the end of the array is reached, or `len` elements have been copied.
409+
*
410+
* @param xs the array to fill.
411+
* @param start the starting index.
412+
* @param len the maximal number of elements to copy.
413+
* @tparam B the type of the elements of the array.
414+
*
415+
* @note Reuse: $consumesIterator
416+
*
417+
* @usecase def copyToArray(xs: Array[A], start: Int, len: Int): Unit
418+
*
419+
* $willNotTerminateInf
420+
*/
421+
def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): xs.type = iterator().copyToArray(xs, start, len)
399422

400423
/** Defines the prefix of this object's `toString` representation.
424+
*
425+
* It is recommended to return the name of the concrete collection type, but
426+
* not implementation subclasses. For example, for `ListMap` this method should
427+
* return `"ListMap"`, not `"Map"` (the supertype) or `"Node"` (an implementation
428+
* subclass).
429+
*
430+
* It is recommended to overwrite this method even if the default implementation
431+
* returns the correct name, to avoid the implementation using reflection.
401432
*
402433
* @return a string representation which starts the result of `toString`
403434
* applied to this $coll. By default the string prefix is the

collections/src/main/scala/strawman/collection/Iterator.scala

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,57 @@ trait Iterator[+A] extends IterableOnce[A] { self =>
12331233
b
12341234
}
12351235

1236+
/** Copy values produced by this iterator to an array.
1237+
* Fills the given array `xs` starting at index `start`.
1238+
* Copying will stop once either the end of the current iterator is reached,
1239+
* or the end of the array is reached.
1240+
*
1241+
* @param xs the array to fill.
1242+
* @param start the starting index.
1243+
* @tparam B the type of the elements of the array.
1244+
*
1245+
* @note Reuse: $consumesIterator
1246+
*
1247+
* @usecase def copyToArray(xs: Array[A], start: Int): Unit
1248+
*
1249+
* $willNotTerminateInf
1250+
*/
1251+
@`inline` final def copyToArray[B >: A](xs: Array[B], start: Int = 0): xs.type = {
1252+
var i = start
1253+
while (i < xs.length && hasNext) {
1254+
xs(i) = next()
1255+
i += 1
1256+
}
1257+
xs
1258+
}
1259+
1260+
/** Copy values produced by this iterator to an array.
1261+
* Fills the given array `xs` starting at index `start` with at most
1262+
* `len` values produced by this iterator.
1263+
* Copying will stop once either the end of the current iterator is reached,
1264+
* or the end of the array is reached, or `len` elements have been copied.
1265+
*
1266+
* @param xs the array to fill.
1267+
* @param start the starting index.
1268+
* @param len the maximal number of elements to copy.
1269+
* @tparam B the type of the elements of the array.
1270+
*
1271+
* @note Reuse: $consumesIterator
1272+
*
1273+
* @usecase def copyToArray(xs: Array[A], start: Int, len: Int): Unit
1274+
*
1275+
* $willNotTerminateInf
1276+
*/
1277+
def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): xs.type = {
1278+
var i = start
1279+
val end = start + math.min(len, xs.length - start)
1280+
while (i < end && hasNext) {
1281+
xs(i) = next()
1282+
i += 1
1283+
}
1284+
xs
1285+
}
1286+
12361287
/** Converts this Iterator into another collection.
12371288
* @return a new collection containing all elements of this Iterator.
12381289
* @tparam C The collection type to build.
@@ -1241,6 +1292,13 @@ trait Iterator[+A] extends IterableOnce[A] { self =>
12411292
*/
12421293
def to[C](factory: Factory[A, C]): C = factory.fromSpecific(self)
12431294

1295+
/** Converts this iterator to a string.
1296+
*
1297+
* @return `"empty iterator"` or `"non-empty iterator"`, depending on
1298+
* whether or not the iterator is empty.
1299+
* @note Reuse: $preservesIterator
1300+
*/
1301+
override def toString = (if (hasNext) "non-empty" else "empty")+" iterator"
12441302
}
12451303

12461304
object Iterator extends IterableFactory[Iterator] {
@@ -1508,7 +1566,6 @@ object Iterator extends IterableFactory[Iterator] {
15081566
}
15091567
}
15101568
}
1511-
15121569
}
15131570

15141571
/** Explicit instantiation of the `Iterator` trait to reduce class file size in subclasses. */

collections/src/main/scala/strawman/collection/Map.scala

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,6 @@ trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C]
5252
with PartialFunction[K, V]
5353
with Equals {
5454

55-
/** Similar to fromIterable, but returns a Map collection type */
56-
protected[this] def mapFromIterable[K2, V2](it: Iterable[(K2, V2)]): CC[K2, V2]
57-
5855
def mapFactory: MapFactory[CC]
5956

6057
/** Optionally returns the value associated with a key.
@@ -223,7 +220,7 @@ trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C]
223220
* @return a new $coll resulting from applying the given function
224221
* `f` to each element of this $coll and collecting the results.
225222
*/
226-
def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = mapFromIterable(View.Map(toIterable, f))
223+
def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = mapFactory.from(View.Map(toIterable, f))
227224

228225
/** Builds a new collection by applying a partial function to all elements of this $coll
229226
* on which the function is defined.
@@ -248,7 +245,7 @@ trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C]
248245
* @return a new $coll resulting from applying the given collection-valued function
249246
* `f` to each element of this $coll and concatenating the results.
250247
*/
251-
def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] = mapFromIterable(View.FlatMap(toIterable, f))
248+
def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] = mapFactory.from(View.FlatMap(toIterable, f))
252249

253250
/** Returns a new $coll containing the elements from the left hand operand followed by the elements from the
254251
* right hand operand. The element type of the $coll is the most specific superclass encompassing
@@ -258,7 +255,7 @@ trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C]
258255
* @return a new $coll which contains all elements
259256
* of this $coll followed by all elements of `suffix`.
260257
*/
261-
def concat[V2 >: V](suffix: collection.Iterable[(K, V2)]): CC[K, V2] = mapFromIterable(View.Concat(toIterable, suffix))
258+
def concat[V2 >: V](suffix: collection.Iterable[(K, V2)]): CC[K, V2] = mapFactory.from(View.Concat(toIterable, suffix))
262259

263260
/** Alias for `concat` */
264261
/*@`inline` final*/ def ++ [V2 >: V](xs: collection.Iterable[(K, V2)]): CC[K, V2] = concat(xs)
@@ -269,7 +266,7 @@ trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C]
269266
iterator().map { case (k, v) => s"$k -> $v" }.mkString(start, sep, end)
270267

271268
@deprecated("Consider requiring an immutable Map or fall back to Map.concat ", "2.13.0")
272-
def + [V1 >: V](kv: (K, V1)): CC[K, V1] = mapFromIterable(View.Append(toIterable, kv))
269+
def + [V1 >: V](kv: (K, V1)): CC[K, V1] = mapFactory.from(View.Append(toIterable, kv))
273270
}
274271

275272
/**

collections/src/main/scala/strawman/collection/SortedMap.scala

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _],
2020

2121
def sortedMapFactory: SortedMapFactory[CC]
2222

23-
protected[this] def sortedMapFromIterable[K2, V2](it: collection.Iterable[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2]
24-
2523
def unsorted: Map[K, V]
2624

2725
/**
@@ -136,7 +134,7 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _],
136134
* `f` to each element of this $coll and collecting the results.
137135
*/
138136
def map[K2, V2](f: ((K, V)) => (K2, V2))(implicit ordering: Ordering[K2]): CC[K2, V2] =
139-
sortedMapFromIterable(View.Map[(K, V), (K2, V2)](toIterable, f))
137+
sortedMapFactory.from(View.Map[(K, V), (K2, V2)](toIterable, f))
140138

141139
/** Builds a new sorted map by applying a function to all elements of this $coll
142140
* and using the elements of the resulting collections.
@@ -146,7 +144,7 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _],
146144
* `f` to each element of this $coll and concatenating the results.
147145
*/
148146
def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] =
149-
sortedMapFromIterable(View.FlatMap(toIterable, f))
147+
sortedMapFactory.from(View.FlatMap(toIterable, f))
150148

151149
/** Builds a new sorted map by applying a partial function to all elements of this $coll
152150
* on which the function is defined.
@@ -172,13 +170,13 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _],
172170
* @return a new collection of type `CC[K2, V2]` which contains all elements
173171
* of this $coll followed by all elements of `xs`.
174172
*/
175-
def concat[K2 >: K, V2 >: V](xs: Iterable[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = sortedMapFromIterable(View.Concat(toIterable, xs))
173+
def concat[K2 >: K, V2 >: V](xs: Iterable[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = sortedMapFactory.from(View.Concat(toIterable, xs))
176174

177175
/** Alias for `concat` */
178176
@`inline` final def ++ [K2 >: K, V2 >: V](xs: Iterable[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = concat(xs)
179177

180178
// We override these methods to fix their return type (which would be `Map` otherwise)
181-
override def concat[V2 >: V](xs: collection.Iterable[(K, V2)]): CC[K, V2] = sortedMapFromIterable(View.Concat(toIterable, xs))
179+
override def concat[V2 >: V](xs: collection.Iterable[(K, V2)]): CC[K, V2] = sortedMapFactory.from(View.Concat(toIterable, xs))
182180
override def ++ [V2 >: V](xs: collection.Iterable[(K, V2)]): CC[K, V2] = concat(xs)
183181
// TODO Also override mapValues
184182

collections/src/main/scala/strawman/collection/concurrent/TrieMap.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,6 @@ final class TrieMap[K, V] private (r: AnyRef, rtupd: AtomicReferenceFieldUpdater
666666

667667
def mapFactory: MapFactory[TrieMap] = TrieMap
668668
protected[this] def fromSpecificIterable(coll: collection.Iterable[(K, V)]): TrieMap[K,V] = TrieMap.from(coll)
669-
protected[this] def mapFromIterable[K2, V2](it: collection.Iterable[(K2, V2)]): TrieMap[K2,V2] = TrieMap.from(it)
670669
protected[this] def newSpecificBuilder(): Builder[(K, V), TrieMap[K,V]] = TrieMap.newBuilder[K, V]()
671670

672671
/* internal methods */

collections/src/main/scala/strawman/collection/convert/Wrappers.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,6 @@ private[collection] trait Wrappers {
342342
protected[this] def fromSpecificIterable(coll: Iterable[(K, V)]) = mutable.HashMap.from(coll)
343343
protected[this] def newSpecificBuilder() = mutable.HashMap.newBuilder()
344344
def mapFactory = mutable.HashMap
345-
protected[this] def mapFromIterable[K2, V2](it: Iterable[(K2, V2)]) = mutable.HashMap.from(it)
346345
}
347346

348347
/** Wraps a Java map as a Scala one. If the map is to support concurrent access,
@@ -450,7 +449,6 @@ private[collection] trait Wrappers {
450449
protected[this] def fromSpecificIterable(coll: Iterable[(A, B)]) = mutable.HashMap.from(coll)
451450
protected[this] def newSpecificBuilder() = mutable.HashMap.newBuilder()
452451
def mapFactory = mutable.HashMap
453-
protected[this] def mapFromIterable[K2, V2](it: Iterable[(K2, V2)]) = mutable.HashMap.from(it)
454452
def empty = mutable.HashMap.empty
455453
}
456454

@@ -504,7 +502,6 @@ private[collection] trait Wrappers {
504502
protected[this] def fromSpecificIterable(coll: Iterable[(String, String)]) = mutable.HashMap.from(coll)
505503
protected[this] def newSpecificBuilder() = mutable.HashMap.newBuilder()
506504
def mapFactory = mutable.HashMap
507-
protected[this] def mapFromIterable[K2, V2](it: Iterable[(K2, V2)]) = mutable.HashMap.from(it)
508505
}
509506
}
510507

collections/src/main/scala/strawman/collection/generic/IsIterableLike.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package strawman.collection
22
package generic
33

4-
import scala.{Any, Char}
4+
import scala.{Any, Char, Array}
55
import scala.Predef.{String, implicitly}
66

77
/** A trait which can be used to avoid code duplication when defining extension
@@ -112,6 +112,12 @@ object IsIterableLike {
112112
val conversion = implicitly[String => IterableOps[Char, Iterable, String]]
113113
}
114114

115+
implicit def arrayRepr[T](implicit conv: Array[T] => IterableOps[T, Iterable, Array[T]]): IsIterableLike[Array[T]] =
116+
new IsIterableLike[Array[T]] {
117+
override type A = T
118+
override val conversion: Array[T] => IterableOps[A, Iterable, Array[T]] = conv
119+
}
120+
115121
implicit def iterableRepr[C[X] <: Iterable[X], A0](implicit conv: C[A0] => IterableOps[A0, C, C[A0]]): IsIterableLike[C[A0]] { type A = A0 } =
116122
new IsIterableLike[C[A0]] {
117123
type A = A0

collections/src/main/scala/strawman/collection/immutable/ChampHashMap.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ final class ChampHashMap[K, +V] private[immutable] (val rootNode: MapNode[K, V],
3737

3838
def mapFactory: MapFactory[ChampHashMap] = ChampHashMap
3939

40-
protected[this] def mapFromIterable[K2, V2](it: collection.Iterable[(K2, V2)]): ChampHashMap[K2, V2] = ChampHashMap.from(it)
41-
4240
protected[this] def fromSpecificIterable(coll: collection.Iterable[(K, V)]): ChampHashMap[K, V] = ChampHashMap.from(coll)
4341

4442
protected[this] def newSpecificBuilder(): Builder[(K, V), ChampHashMap[K, V]] = ChampHashMap.newBuilder()

collections/src/main/scala/strawman/collection/immutable/HashMap.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ sealed abstract class HashMap[K, +V]
4141

4242
protected[this] def fromSpecificIterable(coll: collection.Iterable[(K, V)]): HashMap[K, V] = HashMap.from(coll)
4343

44-
protected[this] def mapFromIterable[K2, V2](it: collection.Iterable[(K2, V2)]): HashMap[K2, V2] =
45-
HashMap.from(it)
46-
4744
protected[this] def newSpecificBuilder(): Builder[(K, V), HashMap[K, V]] = HashMap.newBuilder()
4845

4946
def remove(key: K): HashMap[K, V] = removed0(key, computeHash(key), 0)

collections/src/main/scala/strawman/collection/immutable/IntMap.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ sealed abstract class IntMap[+T] extends Map[Int, T]
183183
def addOne(elem: (Int, T)): this.type = { elems = elems + elem; this }
184184
}
185185
def mapFactory: MapFactory[Map] = Map
186-
protected[this] def mapFromIterable[K2, V2](it: strawman.collection.Iterable[(K2, V2)]): Map[K2,V2] = mapFactory.from(it)
187186

188187
override def empty: IntMap[T] = IntMap.Nil
189188

collections/src/main/scala/strawman/collection/immutable/ListMap.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ sealed class ListMap[K, +V]
5252
def iterableFactory = List
5353
def mapFactory = ListMap
5454

55-
protected[this] def mapFromIterable[K2, V2](it: collection.Iterable[(K2, V2)]): ListMap[K2,V2] = ListMap.from(it)
56-
5755
protected[this] def fromSpecificIterable(coll: collection.Iterable[(K, V)]): ListMap[K, V] = ListMap.from(coll)
5856

5957
protected[this] def newSpecificBuilder(): Builder[(K, V), ListMap[K, V]] = ListMap.newBuilder()

collections/src/main/scala/strawman/collection/immutable/LongMap.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ sealed abstract class LongMap[+T] extends Map[Long, T]
174174
def addOne(elem: (Long, T)): this.type = { elems = elems + elem; this }
175175
}
176176
def mapFactory: MapFactory[Map] = Map
177-
protected[this] def mapFromIterable[K2, V2](it: strawman.collection.Iterable[(K2, V2)]): Map[K2,V2] = mapFactory.from(it)
178177

179178
override def empty: LongMap[T] = LongMap.Nil
180179

0 commit comments

Comments
 (0)