1 /***********************************************************************
2  * Copyright (c) 2013-2024 Commonwealth Computer Research, Inc.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Apache License, Version 2.0
5  * which accompanies this distribution and is available at
6  * http://www.opensource.org/licenses/apache2.0.php.
7  ***********************************************************************/
8 
9 package org.locationtech.geomesa.utils.stats
10 
11 import com.google.gson._
12 import org.apache.commons.text.StringEscapeUtils
13 import org.geotools.api.feature.simple.{SimpleFeature, SimpleFeatureType}
14 import org.locationtech.geomesa.curve.TimePeriod.TimePeriod
15 import org.locationtech.geomesa.utils.date.DateUtils.toInstant
16 import org.locationtech.geomesa.utils.geotools._
17 import org.locationtech.geomesa.utils.text.WKTUtils
18 import org.locationtech.jts.geom.Geometry
19 
20 import java.lang.reflect.Type
21 import java.lang.{Double => jDouble, Float => jFloat, Long => jLong}
22 import java.time.{LocalDateTime, ZoneOffset}
23 import java.util.Date
24 import scala.collection.JavaConverters._
25 import scala.reflect.ClassTag
26 
27 /**
28  * Stats used by the StatsIterator to compute various statistics server-side for a given query.
29  */
30 trait Stat {
31 
32   type S <: Stat
33 
34   /**
35     * The simple feature type that this stat operates on
36     *
37     * @return
38     */
39   def sft: SimpleFeatureType
40 
41   /**
42    * Compute statistics based upon the given simple feature.
43    * This method will be called for every SimpleFeature a query returns.
44    *
45    * @param sf feature to evaluate
46    */
47   def observe(sf: SimpleFeature): Unit
48 
49   /**
50     * Tries to remove the given simple feature from the compiled statistics.
51     * Note: may not be possible to un-observe a feature, in which case this method will
52     * have no effect.
53     *
54     * @param sf feature to un-evaluate
55     */
56   def unobserve(sf: SimpleFeature): Unit
57 
58   /**
59    * Add another stat to this stat. Avoids allocating another object.
60    *
61    * @param other the other stat to add
62    */
63   def +=(other: S): Unit
64 
65   /**
66    * Non type-safe add - if stats are not the same type, will throw an exception
67    *
68    * @param other the other stat to add
69    */
70   def +=(other: Stat)(implicit d: DummyImplicit): Unit = this += other.asInstanceOf[S]
71 
72   /**
73     * Combine two stats into a new stat
74     *
75     * @param other the other stat to add
76     */
77   def +(other: S): S
78 
79   /**
80     * Non type-safe add - if stats are not the same type, will throw an exception
81     *
82     * @param other the other stat to add
83     */
84   def +(other: Stat)(implicit d: DummyImplicit): Stat = this + other.asInstanceOf[S]
85 
86   /**
87    * Returns a JSON representation of the [[Stat]]
88    *
89    * @return stat as a json string
90    */
91   def toJson: String = Stat.JSON.toJson(toJsonObject)
92 
93   /**
94     * Returns a representation of the [[Stat]] to be serialized
95     *
96     * This function should return a representation (view) of the [[Stat]] to be serialized as JSON.
97     * Instances of [[Map]] can be used to represent JSON dictionaries or [[Seq]] for JSON arrays.
98     * A [[collection.SortedMap]] such as [[collection.immutable.ListMap]] is recommended if key order
99     * should be deterministic.  Other types may be used but could require the creation and registration
100     * of custom serializers dependent on the JSON framework being utilized (currently [[Gson]]).
101     *
102     * @return stat as a json serializable object
103     */
104   def toJsonObject: Any
105 
106   /**
107    * Necessary method used by the StatIterator. Indicates if the stat has any values or not
108    *
109    * @return true if stat contains values
110    */
111   def isEmpty: Boolean
112 
113   /**
114     * Compares the two stats for equivalence. We don't use standard 'equals' as it gets messy with
115     * mutable state and hash codes
116     *
117     * @param other other stat to compare
118     * @return true if equals
119     */
120   def isEquivalent(other: Stat): Boolean
121 
122   /**
123    * Clears the stat to its original state when first initialized.
124    * Necessary method used by the StatIterator.
125    */
126   def clear(): Unit
127 }
128 
129 /**
130  * This class contains parsers which dictate how to instantiate a particular Stat.
131  * Stats are created by passing a stats string as a query hint (QueryHints.STATS_STRING).
132  *
133  * A valid stats string should adhere to the parsers here:
134  * e.g. "MinMax(attributeName);IteratorCount" or "RangeHistogram(attributeName,10,0,100)"
135  * (see tests for more use cases)
136  */
137 object Stat {
138 
139   private val ScalaMapSerializer = new JsonSerializer[Map[Any,Any]] {
140     def serialize(s: Map[Any,Any], t: Type, jsc: JsonSerializationContext): JsonElement = jsc.serialize(s.asJava)
141   }
142   private val ScalaSeqSerializer = new JsonSerializer[Seq[Any]] {
143     def serialize(s: Seq[Any], t: Type, jsc: JsonSerializationContext): JsonElement = jsc.serialize(s.asJava)
144   }
145   private val StatSerializer = new JsonSerializer[Stat] {
146     def serialize(s: Stat, t: Type, jsc: JsonSerializationContext): JsonElement = jsc.serialize(s.toJsonObject)
147   }
148   private val GeometrySerializer = new JsonSerializer[Geometry] {
149     def serialize(g: Geometry, t: Type, jsc: JsonSerializationContext): JsonElement =
150       new JsonPrimitive(WKTUtils.write(g))
151   }
152   private val DateSerializer = new JsonSerializer[Date] {
153     def serialize(d: Date, t: Type, jsc: JsonSerializationContext): JsonElement =
154       new JsonPrimitive(GeoToolsDateFormat.format(toInstant(d)))
155   }
156   private val DoubleSerializer = new JsonSerializer[jDouble]() {
157     def serialize(double: jDouble, t: Type, jsc: JsonSerializationContext): JsonElement = double match {
158       /* NaN check, use null to mirror existing behavior for missing/invalid values */
159       case d if jDouble.isNaN(d) => JsonNull.INSTANCE
160       case d if d == jDouble.NEGATIVE_INFINITY => new JsonPrimitive("Infinity")
161       case d if d == jDouble.POSITIVE_INFINITY => new JsonPrimitive("+Infinity")
162       case _ => new JsonPrimitive(double)
163     }
164   }
165   private val FloatSerializer = new JsonSerializer[jFloat]() {
166     def serialize(float: jFloat, t: Type, jsc: JsonSerializationContext): JsonElement = float match {
167       /* NaN check, use null to mirror existing behavior for missing/invalid values */
168       case f if jFloat.isNaN(f) => JsonNull.INSTANCE
169       case f if f == jFloat.NEGATIVE_INFINITY => new JsonPrimitive("Infinity")
170       case f if f == jFloat.POSITIVE_INFINITY => new JsonPrimitive("+Infinity")
171       case _ => new JsonPrimitive(float)
172     }
173   }
174 
175   private val JSON: Gson = new GsonBuilder()
176     .serializeNulls()
177     .registerTypeAdapter(classOf[Double], DoubleSerializer)
178     .registerTypeAdapter(classOf[jDouble], DoubleSerializer)
179     .registerTypeAdapter(classOf[Float], FloatSerializer)
180     .registerTypeAdapter(classOf[jFloat], FloatSerializer)
181     .registerTypeHierarchyAdapter(classOf[Stat], StatSerializer)
182     .registerTypeHierarchyAdapter(classOf[Geometry], GeometrySerializer)
183     .registerTypeHierarchyAdapter(classOf[Date], DateSerializer)
184     .registerTypeHierarchyAdapter(classOf[Map[_,_]], ScalaMapSerializer)
185     .registerTypeHierarchyAdapter(classOf[Seq[_]], ScalaSeqSerializer)
186     .create()
187 
188   def apply(sft: SimpleFeatureType, s: String): Stat = StatParser.parse(sft, s)
189 
190   /**
191     * String that will be parsed to a count stat
192     *
193     * @return
194     */
195   def Count(): String = "Count()"
196 
197   /**
198     * String that will be parsed to a min/max stat
199     *
200     * @param attribute attribute name to min/max
201     * @return
202     */
203   def MinMax(attribute: String): String = s"MinMax(${safeString(attribute)})"
204 
205   /**
206     * String that will be parsed to a histogram stat
207     *
208     * @param attribute attribute name to histogram
209     * @return
210     */
211   def Enumeration(attribute: String): String = s"Enumeration(${safeString(attribute)})"
212 
213   /**
214     * String that will be parsed into a TopK stat
215     *
216     * @param attribute attribute name to evaluate
217     * @return
218     */
219   def TopK(attribute: String): String = s"TopK(${safeString(attribute)})"
220 
221   /**
222     * String that will be parsed into a count min sketch stat
223     *
224     * @param attribute attribute to sketch
225     * @param precision precision of the sketch - @see Frequency
226     * @return
227     */
228   def Frequency(attribute: String, precision: Int): String =
229     s"Frequency(${safeString(attribute)},$precision)"
230 
231   /**
232     * String that will be parsed into a count min sketch stat
233     *
234     * @param attribute attribute to sketch
235     * @param dtg date attribute to use for binning
236     * @param period time period to split on
237     * @param precision precision of the sketch - @see Frequency
238     * @return
239     */
240   def Frequency(attribute: String, dtg: String, period: TimePeriod, precision: Int): String =
241     s"Frequency(${safeString(attribute)},${safeString(dtg)},$period,$precision)"
242 
243   /**
244     * String that will be parsed into a z3 count min sketch stat
245     *
246     * @param geom geometry attribute
247     * @param dtg date attribute
248     * @param period time period to split on
249     * @param precision precision of the z value - @see FrequencyZ3
250     * @return
251     */
252   def Z3Frequency(geom: String, dtg: String, period: TimePeriod, precision: Int): String =
253     s"Z3Frequency(${safeString(geom)},${safeString(dtg)},$period,$precision)"
254 
255   /**
256     * String that will be parsed to a binned histogram stat
257     *
258     * @param attribute attribute name to histogram
259     * @param bins the number of bins to create
260     * @param min min value for the histogram
261     * @param max max value for the histogram
262     * @tparam T class type of the histogram attribute
263     * @return
264     */
265   def Histogram[T](attribute: String, bins: Int, min: T, max: T)(implicit ct: ClassTag[T]): String = {
266     val stringify = stringifier(ct.runtimeClass)
267     s"Histogram(${safeString(attribute)},$bins,${safeString(stringify(min))},${safeString(stringify(max))})"
268   }
269 
270   /**
271     * String that will be parsed into a z3 range histogram stat
272     *
273     * @param geom geometry attribute
274     * @param dtg date attribute
275     * @param period time period to split on
276     * @param length number of the bins per week - @see RangeHistogramZ3
277     * @return
278     */
279   def Z3Histogram(geom: String, dtg: String, period: TimePeriod, length: Int): String =
280     s"Z3Histogram(${safeString(geom)},${safeString(dtg)},$period,$length)"
281 
282   /**
283     * String that will be parsed to a iterator stack counter
284     *
285     * @return
286     */
287   def IteratorStackCount(): String = "IteratorStackCount()"
288 
289   /**
290     * String that will be parsed to a sequence of stat
291     *
292     * @param stats input strings that will be parsed as individual stats
293     * @return
294     */
295   def SeqStat(stats: Seq[String]): String = stats.mkString(";")
296 
297   /**
298     * Groups results by attribute and runs stats for each group.
299     *
300     * @param attribute attribute to group stats by
301     * @param groupedStat stat to apply to grouped attributes
302     * @return
303     */
304   def GroupBy(attribute: String, groupedStat: String): String = s"GroupBy(${safeString(attribute)},$groupedStat)"
305 
306   /**
307     * String that will be parsed into a multi variate descriptive stat
308     *
309     * @param attributes attribute name to evaluate
310     * @return
311     */
312   def DescriptiveStats(attributes: Seq[String]): String = s"DescriptiveStats(${attributes.map(safeString).mkString(",")})"
313 
314   /**
315     * Combines a sequence of stats. This will not modify any of the inputs.
316     *
317     * @param stats stats to combine
318     * @return
319     */
320   def combine[T <: Stat](stats: Seq[T]): Option[T] = {
321     if (stats.length < 2) {
322       stats.headOption
323     } else {
324       // create a new stat so that we don't modify the existing ones
325       val summed = stats.head + stats.tail.head
326       stats.drop(2).foreach(summed += _)
327       Some(summed.asInstanceOf[T])
328     }
329   }
330 
331   // note: adds quotes around the string
332   private def safeString(s: String): String = s""""${StringEscapeUtils.escapeJava(s)}""""
333 
334   /**
335     * Converts a value to a string
336     *
337     * @param clas class of the input value
338     * @param json will the result be used in json? will quote appropriately if so
339     * @tparam T type of input
340     * @return
341     */
342   def stringifier[T](clas: Class[T], json: Boolean = false): Any => String = {
343     val toString: Any => String = if (classOf[Geometry].isAssignableFrom(clas)) {
344       v => WKTUtils.write(v.asInstanceOf[Geometry])
345     } else if (classOf[Date].isAssignableFrom(clas)) {
346       v => GeoToolsDateFormat.format(toInstant(v.asInstanceOf[Date]))
347     } else {
348       v => v.toString
349     }
350 
351     // add quotes to json strings if needed
352     if (json && (!classOf[Number].isAssignableFrom(clas) && clas != classOf[java.lang.Boolean])) {
353       v => if (v == null) { "null" } else { s""""${toString(v)}"""" }
354     } else {
355       v => if (v == null) { "null" } else { toString(v) }
356     }
357   }
358 
359   /**
360     * Converts a string back to a value
361     *
362     * @param clas class of the stringified value
363     * @tparam T type of the value class
364     * @return
365     */
366   def destringifier[T](clas: Class[T]): String => T = {
367     if (clas == classOf[String]) {
368       s => if (s == "null") { null.asInstanceOf[T] } else { s.asInstanceOf[T] }
369     } else if (clas == classOf[Integer]) {
370       s => if (s == "null") { null.asInstanceOf[T] } else { s.toInt.asInstanceOf[T] }
371     } else if (clas == classOf[jLong]) {
372       s => if (s == "null") { null.asInstanceOf[T] } else { s.toLong.asInstanceOf[T] }
373     } else if (clas == classOf[jFloat]) {
374       s => if (s == "null") { null.asInstanceOf[T] } else { s.toFloat.asInstanceOf[T] }
375     } else if (clas == classOf[jDouble]) {
376       s => if (s == "null") { null.asInstanceOf[T] } else { s.toDouble.asInstanceOf[T] }
377     } else if (clas == classOf[java.lang.Boolean]) {
378       s => if (s == "null") { null.asInstanceOf[T] } else { s.toBoolean.asInstanceOf[T] }
379     } else if (classOf[Geometry].isAssignableFrom(clas)) {
380       s => if (s == "null") { null.asInstanceOf[T] } else { WKTUtils.read(s).asInstanceOf[T] }
381     } else if (classOf[Date].isAssignableFrom(clas)) {
382       s => if (s == "null") { null.asInstanceOf[T] } else {
383         Date.from(LocalDateTime.parse(s, GeoToolsDateFormat).toInstant(ZoneOffset.UTC)).asInstanceOf[T]
384       }
385     } else {
386       throw new RuntimeException(s"Unexpected class binding for stat attribute: $clas")
387     }
388   }
389 
390   trait ImmutableStat extends Stat {
391     override def observe(sf: SimpleFeature): Unit = fail()
392     override def unobserve(sf: SimpleFeature): Unit = fail()
393     override def +=(other: S): Unit = fail()
394     override def clear(): Unit = fail()
395 
396     private def fail(): Unit = throw new RuntimeException("This stat is immutable")
397   }
398 }
Line Stmt Id Pos Tree Symbol Tests Code
70 14367 2289 - 2310 TypeApply scala.Any.asInstanceOf other.asInstanceOf[Stat.this.S]
70 14368 2281 - 2310 Apply org.locationtech.geomesa.utils.stats.Stat.+= this.+=(other.asInstanceOf[Stat.this.S])
84 14369 2639 - 2660 TypeApply scala.Any.asInstanceOf other.asInstanceOf[Stat.this.S]
84 14370 2632 - 2660 Apply org.locationtech.geomesa.utils.stats.Stat.+ this.+(other.asInstanceOf[Stat.this.S])
91 14371 2805 - 2817 Select org.locationtech.geomesa.utils.stats.Stat.toJsonObject Stat.this.toJsonObject
91 14372 2788 - 2818 Apply com.google.gson.Gson.toJson Stat.JSON.toJson(Stat.this.toJsonObject)
139 14375 4491 - 4494 Apply org.locationtech.geomesa.utils.stats.Stat.$anon.<init> new $anon()
140 14373 4630 - 4638 Select scala.collection.convert.Decorators.AsJava.asJava scala.collection.JavaConverters.mapAsJavaMapConverter[Any, Any](s).asJava
140 14374 4616 - 4639 Apply com.google.gson.JsonSerializationContext.serialize jsc.serialize(scala.collection.JavaConverters.mapAsJavaMapConverter[Any, Any](s).asJava)
142 14378 4679 - 4682 Apply org.locationtech.geomesa.utils.stats.Stat.$anon.<init> new $anon()
143 14376 4810 - 4818 Select scala.collection.convert.Decorators.AsJava.asJava scala.collection.JavaConverters.seqAsJavaListConverter[Any](s).asJava
143 14377 4796 - 4819 Apply com.google.gson.JsonSerializationContext.serialize jsc.serialize(scala.collection.JavaConverters.seqAsJavaListConverter[Any](s).asJava)
145 14381 4855 - 4858 Apply org.locationtech.geomesa.utils.stats.Stat.$anon.<init> new $anon()
146 14379 4978 - 4992 Select org.locationtech.geomesa.utils.stats.Stat.toJsonObject s.toJsonObject
146 14380 4964 - 4993 Apply com.google.gson.JsonSerializationContext.serialize jsc.serialize(s.toJsonObject)
148 14384 5033 - 5036 Apply org.locationtech.geomesa.utils.stats.Stat.$anon.<init> new $anon()
150 14382 5174 - 5191 Apply org.locationtech.geomesa.utils.text.WKTUtils.write org.locationtech.geomesa.utils.text.WKTUtils.write(g)
150 14383 5156 - 5192 Apply com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive(org.locationtech.geomesa.utils.text.WKTUtils.write(g))
152 14388 5228 - 5231 Apply org.locationtech.geomesa.utils.stats.Stat.$anon.<init> new $anon()
154 14385 5387 - 5399 Apply org.locationtech.geomesa.utils.date.DateUtils.toInstant org.locationtech.geomesa.utils.date.DateUtils.toInstant(d)
154 14386 5361 - 5400 Apply java.time.format.DateTimeFormatter.format org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat.format(org.locationtech.geomesa.utils.date.DateUtils.toInstant(d))
154 14387 5343 - 5401 Apply com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive(org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat.format(org.locationtech.geomesa.utils.date.DateUtils.toInstant(d)))
156 14401 5439 - 5442 Apply org.locationtech.geomesa.utils.stats.Stat.$anon.<init> new $anon()
159 14389 5693 - 5694 ApplyImplicitView scala.Predef.Double2double scala.Predef.Double2double(d)
159 14390 5679 - 5695 Apply java.lang.Double.isNaN java.lang.Double.isNaN(scala.Predef.Double2double(d))
159 14391 5699 - 5716 Select com.google.gson.JsonNull.INSTANCE com.google.gson.JsonNull.INSTANCE
159 14392 5699 - 5716 Block com.google.gson.JsonNull.INSTANCE com.google.gson.JsonNull.INSTANCE
160 14393 5733 - 5763 Apply java.lang.Object.== d.==(-Infinity)
160 14394 5767 - 5796 Apply com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive("Infinity")
160 14395 5767 - 5796 Block com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive("Infinity")
161 14396 5813 - 5843 Apply java.lang.Object.== d.==(Infinity)
161 14397 5847 - 5877 Apply com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive("+Infinity")
161 14398 5847 - 5877 Block com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive("+Infinity")
162 14399 5894 - 5919 Apply com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive(double)
162 14400 5894 - 5919 Block com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive(double)
165 14414 5962 - 5965 Apply org.locationtech.geomesa.utils.stats.Stat.$anon.<init> new $anon()
168 14402 6211 - 6212 ApplyImplicitView scala.Predef.Float2float scala.Predef.Float2float(f)
168 14403 6198 - 6213 Apply java.lang.Float.isNaN java.lang.Float.isNaN(scala.Predef.Float2float(f))
168 14404 6217 - 6234 Select com.google.gson.JsonNull.INSTANCE com.google.gson.JsonNull.INSTANCE
168 14405 6217 - 6234 Block com.google.gson.JsonNull.INSTANCE com.google.gson.JsonNull.INSTANCE
169 14406 6251 - 6280 Apply java.lang.Object.== f.==(-Infinity)
169 14407 6284 - 6313 Apply com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive("Infinity")
169 14408 6284 - 6313 Block com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive("Infinity")
170 14409 6330 - 6359 Apply java.lang.Object.== f.==(Infinity)
170 14410 6363 - 6393 Apply com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive("+Infinity")
170 14411 6363 - 6393 Block com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive("+Infinity")
171 14412 6410 - 6434 Apply com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive(float)
171 14413 6410 - 6434 Block com.google.gson.JsonPrimitive.<init> new com.google.gson.JsonPrimitive(float)
186 14415 6473 - 7111 Apply com.google.gson.GsonBuilder.create new com.google.gson.GsonBuilder().serializeNulls().registerTypeAdapter(classOf[scala.Double], Stat.this.DoubleSerializer).registerTypeAdapter(classOf[java.lang.Double], Stat.this.DoubleSerializer).registerTypeAdapter(classOf[scala.Float], Stat.this.FloatSerializer).registerTypeAdapter(classOf[java.lang.Float], Stat.this.FloatSerializer).registerTypeHierarchyAdapter(classOf[org.locationtech.geomesa.utils.stats.Stat], Stat.this.StatSerializer).registerTypeHierarchyAdapter(classOf[org.locationtech.jts.geom.Geometry], Stat.this.GeometrySerializer).registerTypeHierarchyAdapter(classOf[java.util.Date], Stat.this.DateSerializer).registerTypeHierarchyAdapter(classOf[scala.collection.immutable.Map], Stat.this.ScalaMapSerializer).registerTypeHierarchyAdapter(classOf[scala.collection.Seq], Stat.this.ScalaSeqSerializer).create()
188 14416 7168 - 7192 Apply org.locationtech.geomesa.utils.stats.StatParser.parse StatParser.parse(sft, s, StatParser.parse$default$3)
195 14417 7300 - 7309 Literal <nosymbol> "Count()"
203 14418 7488 - 7496 Literal <nosymbol> "MinMax("
203 14419 7519 - 7521 Literal <nosymbol> ")"
203 14420 7497 - 7518 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(attribute)
203 14421 7486 - 7521 Apply scala.StringContext.s scala.StringContext.apply("MinMax(", ")").s(Stat.this.safeString(attribute))
211 14422 7709 - 7722 Literal <nosymbol> "Enumeration("
211 14423 7745 - 7747 Literal <nosymbol> ")"
211 14424 7723 - 7744 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(attribute)
211 14425 7707 - 7747 Apply scala.StringContext.s scala.StringContext.apply("Enumeration(", ")").s(Stat.this.safeString(attribute))
219 14426 7924 - 7930 Literal <nosymbol> "TopK("
219 14427 7953 - 7955 Literal <nosymbol> ")"
219 14428 7931 - 7952 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(attribute)
219 14429 7922 - 7955 Apply scala.StringContext.s scala.StringContext.apply("TopK(", ")").s(Stat.this.safeString(attribute))
229 14430 8226 - 8237 Literal <nosymbol> "Frequency("
229 14431 8260 - 8262 Literal <nosymbol> ","
229 14432 8271 - 8273 Literal <nosymbol> ")"
229 14433 8238 - 8259 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(attribute)
229 14434 8224 - 8273 Apply scala.StringContext.s scala.StringContext.apply("Frequency(", ",", ")").s(Stat.this.safeString(attribute), precision)
241 14435 8672 - 8683 Literal <nosymbol> "Frequency("
241 14436 8706 - 8708 Literal <nosymbol> ","
241 14437 8725 - 8727 Literal <nosymbol> ","
241 14438 8733 - 8735 Literal <nosymbol> ","
241 14439 8744 - 8746 Literal <nosymbol> ")"
241 14440 8684 - 8705 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(attribute)
241 14441 8709 - 8724 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(dtg)
241 14442 8670 - 8746 Apply scala.StringContext.s scala.StringContext.apply("Frequency(", ",", ",", ",", ")").s(Stat.this.safeString(attribute), Stat.this.safeString(dtg), period, precision)
253 14443 9123 - 9136 Literal <nosymbol> "Z3Frequency("
253 14444 9154 - 9156 Literal <nosymbol> ","
253 14445 9173 - 9175 Literal <nosymbol> ","
253 14446 9181 - 9183 Literal <nosymbol> ","
253 14447 9192 - 9194 Literal <nosymbol> ")"
253 14448 9137 - 9153 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(geom)
253 14449 9157 - 9172 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(dtg)
253 14450 9121 - 9194 Apply scala.StringContext.s scala.StringContext.apply("Z3Frequency(", ",", ",", ",", ")").s(Stat.this.safeString(geom), Stat.this.safeString(dtg), period, precision)
266 14451 9666 - 9681 Select scala.reflect.ClassTag.runtimeClass ct.runtimeClass
266 14452 9654 - 9654 TypeApply org.locationtech.geomesa.utils.stats.Stat.stringifier$default$2 Stat.this.stringifier$default$2[Nothing]
266 14453 9654 - 9682 Apply org.locationtech.geomesa.utils.stats.Stat.stringifier Stat.this.stringifier[_$1](ct.runtimeClass, Stat.this.stringifier$default$2[Nothing])
267 14454 9689 - 9700 Literal <nosymbol> "Histogram("
267 14455 9723 - 9725 Literal <nosymbol> ","
267 14456 9729 - 9731 Literal <nosymbol> ","
267 14457 9759 - 9761 Literal <nosymbol> ","
267 14458 9789 - 9791 Literal <nosymbol> ")"
267 14459 9701 - 9722 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(attribute)
267 14460 9743 - 9757 Apply scala.Function1.apply stringify.apply(min)
267 14461 9732 - 9758 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(stringify.apply(min))
267 14462 9773 - 9787 Apply scala.Function1.apply stringify.apply(max)
267 14463 9762 - 9788 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(stringify.apply(max))
267 14464 9687 - 9791 Apply scala.StringContext.s scala.StringContext.apply("Histogram(", ",", ",", ",", ")").s(Stat.this.safeString(attribute), bins, Stat.this.safeString(stringify.apply(min)), Stat.this.safeString(stringify.apply(max)))
280 14465 10173 - 10186 Literal <nosymbol> "Z3Histogram("
280 14466 10204 - 10206 Literal <nosymbol> ","
280 14467 10223 - 10225 Literal <nosymbol> ","
280 14468 10231 - 10233 Literal <nosymbol> ","
280 14469 10239 - 10241 Literal <nosymbol> ")"
280 14470 10187 - 10203 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(geom)
280 14471 10207 - 10222 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(dtg)
280 14472 10171 - 10241 Apply scala.StringContext.s scala.StringContext.apply("Z3Histogram(", ",", ",", ",", ")").s(Stat.this.safeString(geom), Stat.this.safeString(dtg), period, length)
287 14473 10374 - 10396 Literal <nosymbol> "IteratorStackCount()"
295 14474 10603 - 10622 Apply scala.collection.TraversableOnce.mkString stats.mkString(";")
304 14475 10900 - 10909 Literal <nosymbol> "GroupBy("
304 14476 10932 - 10934 Literal <nosymbol> ","
304 14477 10945 - 10947 Literal <nosymbol> ")"
304 14478 10910 - 10931 Apply org.locationtech.geomesa.utils.stats.Stat.safeString Stat.this.safeString(attribute)
304 14479 10898 - 10947 Apply scala.StringContext.s scala.StringContext.apply("GroupBy(", ",", ")").s(Stat.this.safeString(attribute), groupedStat)
312 14480 11164 - 11182 Literal <nosymbol> "DescriptiveStats("
312 14481 11224 - 11226 Literal <nosymbol> ")"
312 14482 11183 - 11223 Apply scala.collection.TraversableOnce.mkString attributes.map[String, Seq[String]]({ ((s: String) => Stat.this.safeString(s)) })(collection.this.Seq.canBuildFrom[String]).mkString(",")
312 14483 11162 - 11226 Apply scala.StringContext.s scala.StringContext.apply("DescriptiveStats(", ")").s(attributes.map[String, Seq[String]]({ ((s: String) => Stat.this.safeString(s)) })(collection.this.Seq.canBuildFrom[String]).mkString(","))
321 14484 11436 - 11452 Apply scala.Int.< stats.length.<(2)
322 14485 11462 - 11478 Select scala.collection.TraversableLike.headOption stats.headOption
322 14486 11462 - 11478 Block scala.collection.TraversableLike.headOption stats.headOption
323 14496 11490 - 11690 Block <nosymbol> { val summed: org.locationtech.geomesa.utils.stats.Stat = stats.head.+(stats.tail.head)(Predef.this.DummyImplicit.dummyImplicit); stats.drop(2).foreach[Unit](((x$1: T) => summed.+=(x$1)(Predef.this.DummyImplicit.dummyImplicit))); scala.Some.apply[T](summed.asInstanceOf[T]) }
325 14487 11593 - 11608 Select scala.collection.IterableLike.head stats.tail.head
325 14488 11591 - 11591 Select scala.Predef.DummyImplicit.dummyImplicit Predef.this.DummyImplicit.dummyImplicit
325 14489 11580 - 11608 ApplyToImplicitArgs org.locationtech.geomesa.utils.stats.Stat.+ stats.head.+(stats.tail.head)(Predef.this.DummyImplicit.dummyImplicit)
326 14490 11626 - 11627 Literal <nosymbol> 2
326 14491 11644 - 11644 Select scala.Predef.DummyImplicit.dummyImplicit Predef.this.DummyImplicit.dummyImplicit
326 14492 11637 - 11648 ApplyToImplicitArgs org.locationtech.geomesa.utils.stats.Stat.+= summed.+=(x$1)(Predef.this.DummyImplicit.dummyImplicit)
326 14493 11615 - 11649 Apply scala.collection.IterableLike.foreach stats.drop(2).foreach[Unit](((x$1: T) => summed.+=(x$1)(Predef.this.DummyImplicit.dummyImplicit)))
327 14494 11661 - 11683 TypeApply scala.Any.asInstanceOf summed.asInstanceOf[T]
327 14495 11656 - 11684 Apply scala.Some.apply scala.Some.apply[T](summed.asInstanceOf[T])
332 14497 11787 - 11789 Literal <nosymbol> "\""
332 14498 11822 - 11826 Literal <nosymbol> "\""
332 14499 11790 - 11821 Apply org.apache.commons.text.StringEscapeUtils.escapeJava org.apache.commons.text.StringEscapeUtils.escapeJava(s)
332 14500 11783 - 11826 Apply scala.StringContext.s scala.StringContext.apply("\"", "\"").s(org.apache.commons.text.StringEscapeUtils.escapeJava(s))
343 14501 12168 - 12208 Apply java.lang.Class.isAssignableFrom classOf[org.locationtech.jts.geom.Geometry].isAssignableFrom(clas)
344 14502 12238 - 12262 TypeApply scala.Any.asInstanceOf v.asInstanceOf[org.locationtech.jts.geom.Geometry]
344 14503 12223 - 12263 Apply org.locationtech.geomesa.utils.text.WKTUtils.write org.locationtech.geomesa.utils.text.WKTUtils.write(v.asInstanceOf[org.locationtech.jts.geom.Geometry])
344 14504 12218 - 12263 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((v: Any) => org.locationtech.geomesa.utils.text.WKTUtils.write(v.asInstanceOf[org.locationtech.jts.geom.Geometry]))
345 14505 12279 - 12315 Apply java.lang.Class.isAssignableFrom classOf[java.util.Date].isAssignableFrom(clas)
345 14512 12275 - 12429 If <nosymbol> if (classOf[java.util.Date].isAssignableFrom(clas)) ((v: Any) => org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat.format(org.locationtech.geomesa.utils.date.DateUtils.toInstant(v.asInstanceOf[java.util.Date]))) else ((v: Any) => v.toString())
346 14506 12366 - 12386 TypeApply scala.Any.asInstanceOf v.asInstanceOf[java.util.Date]
346 14507 12356 - 12387 Apply org.locationtech.geomesa.utils.date.DateUtils.toInstant org.locationtech.geomesa.utils.date.DateUtils.toInstant(v.asInstanceOf[java.util.Date])
346 14508 12330 - 12388 Apply java.time.format.DateTimeFormatter.format org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat.format(org.locationtech.geomesa.utils.date.DateUtils.toInstant(v.asInstanceOf[java.util.Date]))
346 14509 12325 - 12388 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((v: Any) => org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat.format(org.locationtech.geomesa.utils.date.DateUtils.toInstant(v.asInstanceOf[java.util.Date])))
348 14510 12413 - 12423 Apply scala.Any.toString v.toString()
348 14511 12408 - 12423 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((v: Any) => v.toString())
352 14513 12493 - 12508 Literal <nosymbol> classOf[java.lang.Number]
352 14514 12535 - 12569 Apply java.lang.Object.!= clas.!=(classOf[java.lang.Boolean])
352 14515 12492 - 12569 Apply scala.Boolean.&& classOf[java.lang.Number].isAssignableFrom(clas).unary_!.&&(clas.!=(classOf[java.lang.Boolean]))
352 14516 12483 - 12570 Apply scala.Boolean.&& json.&&(classOf[java.lang.Number].isAssignableFrom(clas).unary_!.&&(clas.!=(classOf[java.lang.Boolean])))
353 14517 12589 - 12598 Apply scala.Any.== v.==(null)
353 14518 12602 - 12608 Literal <nosymbol> "null"
353 14519 12602 - 12608 Block <nosymbol> "null"
353 14520 12622 - 12624 Literal <nosymbol> "\""
353 14521 12637 - 12641 Literal <nosymbol> "\""
353 14522 12625 - 12636 Apply scala.Function1.apply toString.apply(v)
353 14523 12618 - 12641 Apply scala.StringContext.s scala.StringContext.apply("\"", "\"").s(toString.apply(v))
353 14524 12618 - 12641 Block scala.StringContext.s scala.StringContext.apply("\"", "\"").s(toString.apply(v))
353 14525 12580 - 12643 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((v: Any) => if (v.==(null)) "null" else scala.StringContext.apply("\"", "\"").s(toString.apply(v)))
355 14526 12672 - 12681 Apply scala.Any.== v.==(null)
355 14527 12685 - 12691 Literal <nosymbol> "null"
355 14528 12685 - 12691 Block <nosymbol> "null"
355 14529 12701 - 12712 Apply scala.Function1.apply toString.apply(v)
355 14530 12701 - 12712 Block scala.Function1.apply toString.apply(v)
355 14531 12663 - 12714 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((v: Any) => if (v.==(null)) "null" else toString.apply(v))
367 14532 12952 - 12975 Apply java.lang.Object.== clas.==(classOf[java.lang.String])
368 14533 12994 - 13005 Apply java.lang.Object.== s.==("null")
368 14534 13009 - 13013 Literal <nosymbol> null
368 14535 13009 - 13029 TypeApply scala.Any.asInstanceOf null.asInstanceOf[T]
368 14536 13009 - 13029 Block scala.Any.asInstanceOf null.asInstanceOf[T]
368 14537 13039 - 13056 TypeApply scala.Any.asInstanceOf s.asInstanceOf[T]
368 14538 13039 - 13056 Block scala.Any.asInstanceOf s.asInstanceOf[T]
368 14539 12985 - 13058 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((s: String) => if (s.==("null")) null.asInstanceOf[T] else s.asInstanceOf[T])
369 14540 13074 - 13098 Apply java.lang.Object.== clas.==(classOf[java.lang.Integer])
369 14607 13070 - 14208 If <nosymbol> if (clas.==(classOf[java.lang.Integer])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toInt.asInstanceOf[T]) else if (clas.==(classOf[java.lang.Long])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toLong.asInstanceOf[T]) else if (clas.==(classOf[java.lang.Float])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toFloat.asInstanceOf[T]) else if (clas.==(classOf[java.lang.Double])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toDouble.asInstanceOf[T]) else if (clas.==(classOf[java.lang.Boolean])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toBoolean.asInstanceOf[T]) else if (classOf[org.locationtech.jts.geom.Geometry].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else org.locationtech.geomesa.utils.text.WKTUtils.read(s).asInstanceOf[T]) else if (classOf[java.util.Date].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else java.util.Date.from(java.time.LocalDateTime.parse(s, org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat).toInstant(java.time.ZoneOffset.UTC)).asInstanceOf[T]) else throw new scala.`package`.RuntimeException(scala.StringContext.apply("Unexpected class binding for stat attribute: ", "").s(clas))
370 14541 13117 - 13128 Apply java.lang.Object.== s.==("null")
370 14542 13132 - 13136 Literal <nosymbol> null
370 14543 13132 - 13152 TypeApply scala.Any.asInstanceOf null.asInstanceOf[T]
370 14544 13132 - 13152 Block scala.Any.asInstanceOf null.asInstanceOf[T]
370 14545 13162 - 13185 TypeApply scala.Any.asInstanceOf scala.Predef.augmentString(s).toInt.asInstanceOf[T]
370 14546 13162 - 13185 Block scala.Any.asInstanceOf scala.Predef.augmentString(s).toInt.asInstanceOf[T]
370 14547 13108 - 13187 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toInt.asInstanceOf[T])
371 14548 13203 - 13225 Apply java.lang.Object.== clas.==(classOf[java.lang.Long])
371 14606 13199 - 14208 If <nosymbol> if (clas.==(classOf[java.lang.Long])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toLong.asInstanceOf[T]) else if (clas.==(classOf[java.lang.Float])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toFloat.asInstanceOf[T]) else if (clas.==(classOf[java.lang.Double])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toDouble.asInstanceOf[T]) else if (clas.==(classOf[java.lang.Boolean])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toBoolean.asInstanceOf[T]) else if (classOf[org.locationtech.jts.geom.Geometry].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else org.locationtech.geomesa.utils.text.WKTUtils.read(s).asInstanceOf[T]) else if (classOf[java.util.Date].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else java.util.Date.from(java.time.LocalDateTime.parse(s, org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat).toInstant(java.time.ZoneOffset.UTC)).asInstanceOf[T]) else throw new scala.`package`.RuntimeException(scala.StringContext.apply("Unexpected class binding for stat attribute: ", "").s(clas))
372 14549 13244 - 13255 Apply java.lang.Object.== s.==("null")
372 14550 13259 - 13263 Literal <nosymbol> null
372 14551 13259 - 13279 TypeApply scala.Any.asInstanceOf null.asInstanceOf[T]
372 14552 13259 - 13279 Block scala.Any.asInstanceOf null.asInstanceOf[T]
372 14553 13289 - 13313 TypeApply scala.Any.asInstanceOf scala.Predef.augmentString(s).toLong.asInstanceOf[T]
372 14554 13289 - 13313 Block scala.Any.asInstanceOf scala.Predef.augmentString(s).toLong.asInstanceOf[T]
372 14555 13235 - 13315 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toLong.asInstanceOf[T])
373 14556 13331 - 13354 Apply java.lang.Object.== clas.==(classOf[java.lang.Float])
373 14605 13327 - 14208 If <nosymbol> if (clas.==(classOf[java.lang.Float])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toFloat.asInstanceOf[T]) else if (clas.==(classOf[java.lang.Double])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toDouble.asInstanceOf[T]) else if (clas.==(classOf[java.lang.Boolean])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toBoolean.asInstanceOf[T]) else if (classOf[org.locationtech.jts.geom.Geometry].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else org.locationtech.geomesa.utils.text.WKTUtils.read(s).asInstanceOf[T]) else if (classOf[java.util.Date].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else java.util.Date.from(java.time.LocalDateTime.parse(s, org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat).toInstant(java.time.ZoneOffset.UTC)).asInstanceOf[T]) else throw new scala.`package`.RuntimeException(scala.StringContext.apply("Unexpected class binding for stat attribute: ", "").s(clas))
374 14557 13373 - 13384 Apply java.lang.Object.== s.==("null")
374 14558 13388 - 13392 Literal <nosymbol> null
374 14559 13388 - 13408 TypeApply scala.Any.asInstanceOf null.asInstanceOf[T]
374 14560 13388 - 13408 Block scala.Any.asInstanceOf null.asInstanceOf[T]
374 14561 13418 - 13443 TypeApply scala.Any.asInstanceOf scala.Predef.augmentString(s).toFloat.asInstanceOf[T]
374 14562 13418 - 13443 Block scala.Any.asInstanceOf scala.Predef.augmentString(s).toFloat.asInstanceOf[T]
374 14563 13364 - 13445 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toFloat.asInstanceOf[T])
375 14564 13461 - 13485 Apply java.lang.Object.== clas.==(classOf[java.lang.Double])
375 14604 13457 - 14208 If <nosymbol> if (clas.==(classOf[java.lang.Double])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toDouble.asInstanceOf[T]) else if (clas.==(classOf[java.lang.Boolean])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toBoolean.asInstanceOf[T]) else if (classOf[org.locationtech.jts.geom.Geometry].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else org.locationtech.geomesa.utils.text.WKTUtils.read(s).asInstanceOf[T]) else if (classOf[java.util.Date].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else java.util.Date.from(java.time.LocalDateTime.parse(s, org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat).toInstant(java.time.ZoneOffset.UTC)).asInstanceOf[T]) else throw new scala.`package`.RuntimeException(scala.StringContext.apply("Unexpected class binding for stat attribute: ", "").s(clas))
376 14565 13504 - 13515 Apply java.lang.Object.== s.==("null")
376 14566 13519 - 13523 Literal <nosymbol> null
376 14567 13519 - 13539 TypeApply scala.Any.asInstanceOf null.asInstanceOf[T]
376 14568 13519 - 13539 Block scala.Any.asInstanceOf null.asInstanceOf[T]
376 14569 13549 - 13575 TypeApply scala.Any.asInstanceOf scala.Predef.augmentString(s).toDouble.asInstanceOf[T]
376 14570 13549 - 13575 Block scala.Any.asInstanceOf scala.Predef.augmentString(s).toDouble.asInstanceOf[T]
376 14571 13495 - 13577 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toDouble.asInstanceOf[T])
377 14572 13593 - 13627 Apply java.lang.Object.== clas.==(classOf[java.lang.Boolean])
377 14603 13589 - 14208 If <nosymbol> if (clas.==(classOf[java.lang.Boolean])) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toBoolean.asInstanceOf[T]) else if (classOf[org.locationtech.jts.geom.Geometry].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else org.locationtech.geomesa.utils.text.WKTUtils.read(s).asInstanceOf[T]) else if (classOf[java.util.Date].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else java.util.Date.from(java.time.LocalDateTime.parse(s, org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat).toInstant(java.time.ZoneOffset.UTC)).asInstanceOf[T]) else throw new scala.`package`.RuntimeException(scala.StringContext.apply("Unexpected class binding for stat attribute: ", "").s(clas))
378 14573 13646 - 13657 Apply java.lang.Object.== s.==("null")
378 14574 13661 - 13665 Literal <nosymbol> null
378 14575 13661 - 13681 TypeApply scala.Any.asInstanceOf null.asInstanceOf[T]
378 14576 13661 - 13681 Block scala.Any.asInstanceOf null.asInstanceOf[T]
378 14577 13691 - 13718 TypeApply scala.Any.asInstanceOf scala.Predef.augmentString(s).toBoolean.asInstanceOf[T]
378 14578 13691 - 13718 Block scala.Any.asInstanceOf scala.Predef.augmentString(s).toBoolean.asInstanceOf[T]
378 14579 13637 - 13720 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((s: String) => if (s.==("null")) null.asInstanceOf[T] else scala.Predef.augmentString(s).toBoolean.asInstanceOf[T])
379 14580 13736 - 13776 Apply java.lang.Class.isAssignableFrom classOf[org.locationtech.jts.geom.Geometry].isAssignableFrom(clas)
379 14602 13732 - 14208 If <nosymbol> if (classOf[org.locationtech.jts.geom.Geometry].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else org.locationtech.geomesa.utils.text.WKTUtils.read(s).asInstanceOf[T]) else if (classOf[java.util.Date].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else java.util.Date.from(java.time.LocalDateTime.parse(s, org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat).toInstant(java.time.ZoneOffset.UTC)).asInstanceOf[T]) else throw new scala.`package`.RuntimeException(scala.StringContext.apply("Unexpected class binding for stat attribute: ", "").s(clas))
380 14581 13795 - 13806 Apply java.lang.Object.== s.==("null")
380 14582 13810 - 13814 Literal <nosymbol> null
380 14583 13810 - 13830 TypeApply scala.Any.asInstanceOf null.asInstanceOf[T]
380 14584 13810 - 13830 Block scala.Any.asInstanceOf null.asInstanceOf[T]
380 14585 13840 - 13872 TypeApply scala.Any.asInstanceOf org.locationtech.geomesa.utils.text.WKTUtils.read(s).asInstanceOf[T]
380 14586 13840 - 13872 Block scala.Any.asInstanceOf org.locationtech.geomesa.utils.text.WKTUtils.read(s).asInstanceOf[T]
380 14587 13786 - 13874 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((s: String) => if (s.==("null")) null.asInstanceOf[T] else org.locationtech.geomesa.utils.text.WKTUtils.read(s).asInstanceOf[T])
381 14588 13890 - 13926 Apply java.lang.Class.isAssignableFrom classOf[java.util.Date].isAssignableFrom(clas)
381 14601 13886 - 14208 If <nosymbol> if (classOf[java.util.Date].isAssignableFrom(clas)) ((s: String) => if (s.==("null")) null.asInstanceOf[T] else java.util.Date.from(java.time.LocalDateTime.parse(s, org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat).toInstant(java.time.ZoneOffset.UTC)).asInstanceOf[T]) else throw new scala.`package`.RuntimeException(scala.StringContext.apply("Unexpected class binding for stat attribute: ", "").s(clas))
382 14589 13945 - 13956 Apply java.lang.Object.== s.==("null")
382 14590 13960 - 13964 Literal <nosymbol> null
382 14591 13960 - 13980 TypeApply scala.Any.asInstanceOf null.asInstanceOf[T]
382 14592 13960 - 13980 Block scala.Any.asInstanceOf null.asInstanceOf[T]
382 14598 13936 - 14101 Function org.locationtech.geomesa.utils.stats.Stat.$anonfun ((s: String) => if (s.==("null")) null.asInstanceOf[T] else java.util.Date.from(java.time.LocalDateTime.parse(s, org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat).toInstant(java.time.ZoneOffset.UTC)).asInstanceOf[T])
383 14593 14031 - 14049 Select org.locationtech.geomesa.utils.geotools.GeoToolsDateFormat org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat
383 14594 14061 - 14075 Select java.time.ZoneOffset.UTC java.time.ZoneOffset.UTC
383 14595 14008 - 14076 Apply java.time.chrono.ChronoLocalDateTime.toInstant java.time.LocalDateTime.parse(s, org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat).toInstant(java.time.ZoneOffset.UTC)
383 14596 13998 - 14093 TypeApply scala.Any.asInstanceOf java.util.Date.from(java.time.LocalDateTime.parse(s, org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat).toInstant(java.time.ZoneOffset.UTC)).asInstanceOf[T]
383 14597 13998 - 14093 Block scala.Any.asInstanceOf java.util.Date.from(java.time.LocalDateTime.parse(s, org.locationtech.geomesa.utils.geotools.`package`.GeoToolsDateFormat).toInstant(java.time.ZoneOffset.UTC)).asInstanceOf[T]
386 14599 14121 - 14202 Throw <nosymbol> throw new scala.`package`.RuntimeException(scala.StringContext.apply("Unexpected class binding for stat attribute: ", "").s(clas))
386 14600 14121 - 14202 Block <nosymbol> throw new scala.`package`.RuntimeException(scala.StringContext.apply("Unexpected class binding for stat attribute: ", "").s(clas))
391 14608 14303 - 14309 Apply org.locationtech.geomesa.utils.stats.Stat.ImmutableStat.fail ImmutableStat.this.fail()
392 14609 14364 - 14370 Apply org.locationtech.geomesa.utils.stats.Stat.ImmutableStat.fail ImmutableStat.this.fail()
393 14610 14409 - 14415 Apply org.locationtech.geomesa.utils.stats.Stat.ImmutableStat.fail ImmutableStat.this.fail()
394 14611 14449 - 14455 Apply org.locationtech.geomesa.utils.stats.Stat.ImmutableStat.fail ImmutableStat.this.fail()
396 14612 14488 - 14540 Throw <nosymbol> throw new scala.`package`.RuntimeException("This stat is immutable")