summaryrefslogtreecommitdiff
path: root/mapbox/src/main/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'mapbox/src/main/java/com')
-rw-r--r--mapbox/src/main/java/com/example/mapbox/MainActivity.kt153
-rw-r--r--mapbox/src/main/java/com/example/mapbox/MainActivityModule.kt10
-rw-r--r--mapbox/src/main/java/com/example/mapbox/MapboxApp.kt16
-rw-r--r--mapbox/src/main/java/com/example/mapbox/breadcrumb/Breadcrumb.kt157
-rw-r--r--mapbox/src/main/java/com/example/mapbox/breadcrumb/ExerciseEngineState.kt6
-rw-r--r--mapbox/src/main/java/com/example/mapbox/compass/WassCompassEngine.kt48
-rw-r--r--mapbox/src/main/java/com/example/mapbox/di/AppComponent.kt19
-rw-r--r--mapbox/src/main/java/com/example/mapbox/extensions/AnnotationsExtensions.kt48
-rw-r--r--mapbox/src/main/java/com/example/mapbox/extensions/LocationExtensions.kt8
-rw-r--r--mapbox/src/main/java/com/example/mapbox/extensions/MapboxMapExtensions.kt22
-rw-r--r--mapbox/src/main/java/com/example/mapbox/extensions/ResourceExtensions.kt25
-rw-r--r--mapbox/src/main/java/com/example/mapbox/livedata/HeadingSensorLiveData.kt33
-rw-r--r--mapbox/src/main/java/com/example/mapbox/livedata/LocationSensorLiveData.kt35
-rw-r--r--mapbox/src/main/java/com/example/mapbox/livedata/LocationWithHeadingLiveData.kt30
-rw-r--r--mapbox/src/main/java/com/example/mapbox/livedata/MapViewSensors.kt37
-rw-r--r--mapbox/src/main/java/com/example/mapbox/mockdata/MockHeadingSensor.kt18
-rw-r--r--mapbox/src/main/java/com/example/mapbox/mockdata/MockLocationSensor.kt31
-rw-r--r--mapbox/src/main/java/com/example/mapbox/mockdata/MockLocations.kt661
-rw-r--r--mapbox/src/main/java/com/example/mapbox/ui/MapboxMapView.kt282
-rw-r--r--mapbox/src/main/java/com/example/mapbox/ui/extensions/ConstraintLayoutExtensions.kt19
20 files changed, 1658 insertions, 0 deletions
diff --git a/mapbox/src/main/java/com/example/mapbox/MainActivity.kt b/mapbox/src/main/java/com/example/mapbox/MainActivity.kt
new file mode 100644
index 0000000000..90e76a1f48
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/MainActivity.kt
@@ -0,0 +1,153 @@
+package com.example.mapbox
+
+import android.annotation.SuppressLint
+import android.location.Location
+import android.os.Bundle
+import android.os.SystemClock
+import android.support.constraint.ConstraintLayout
+import android.support.wearable.activity.WearableActivity
+import android.util.Log
+import android.widget.Toast
+import androidx.lifecycle.Observer
+import com.example.mapbox.ui.MapboxMapView
+import com.example.mapbox.ui.extensions.addViewAndMatchItToParent
+import com.mapbox.android.core.permissions.PermissionsListener
+import com.mapbox.android.core.permissions.PermissionsManager
+import com.mapbox.mapboxsdk.Mapbox
+import com.mapbox.mapboxsdk.maps.MapboxMap
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback
+import com.mapbox.mapboxsdk.testapp.R
+import com.soy.android.maps.compass.WassCompassEngine
+import com.soy.android.maps.livedata.MapViewSensors
+import dagger.android.AndroidInjection
+import javax.inject.Inject
+
+class MainActivity : WearableActivity(), PermissionsListener, OnMapReadyCallback {
+ override fun onMapReady(mapboxMap: MapboxMap) {
+ measureAndPrintTimeMillis("onStart.requestSensorUpdates") {
+ requestSensorUpdates()
+ }
+ mapboxMapView.onMapReady(mapboxMap)
+ }
+
+ private lateinit var mapboxMapView: MapboxMapView
+
+ @Inject
+ lateinit var sensors: MapViewSensors
+
+ @SuppressLint("MissingPermission")
+ override fun onCreate(savedInstanceState: Bundle?) {
+ AndroidInjection.inject(this)
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ if (PermissionsManager.areLocationPermissionsGranted(this)) {
+ createMapboxMapView()
+ } else {
+ PermissionsManager(this).requestLocationPermissions(this)
+ }
+ setAmbientEnabled()
+ }
+
+ private fun createMapboxMapView() {
+ Mapbox.getInstance(this, getString(R.string.mapbox_api_key))
+ val location = sensors.locationLiveData.value
+ val root = findViewById<ConstraintLayout>(R.id.content)
+ mapboxMapView = MapboxMapView(this, location).apply {
+ compassEngine = WassCompassEngine(sensors.headingLiveData)
+ root.addViewAndMatchItToParent(this)
+ onCreate(null)
+ getMapAsync(this@MainActivity)
+ }
+ }
+
+ public override fun onResume() {
+ super.onResume()
+ measureAndPrintTimeMillis("onResume") {
+ mapboxMapView.onResume()
+ }
+ }
+
+ public override fun onPause() {
+ super.onPause()
+ measureAndPrintTimeMillis("onPause") {
+ mapboxMapView.onPause()
+ }
+ }
+
+ override fun onLowMemory() {
+ super.onLowMemory()
+ measureAndPrintTimeMillis("onLowMemory") {
+ mapboxMapView.onLowMemory()
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ measureAndPrintTimeMillis("onStart.mapOnStart") {
+ mapboxMapView.onStart()
+ }
+ }
+
+ override fun onStop() {
+ super.onStop()
+ removeSensorUpdates()
+ measureAndPrintTimeMillis("onStop") {
+ mapboxMapView.onStop()
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ measureAndPrintTimeMillis("onDestroy") {
+ mapboxMapView.onDestroy()
+ }
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ measureAndPrintTimeMillis("onSaveInstanceState") {
+ mapboxMapView.onSaveInstanceState(outState)
+ }
+ }
+
+ private fun requestSensorUpdates() {
+ sensors.requestUpdates(locationObserver)
+ mapboxMapView.compassEngine?.requestUpdates()
+ }
+
+ private fun removeSensorUpdates() {
+ sensors.removeUpdates(locationObserver)
+ mapboxMapView.compassEngine?.removeUpdates()
+ }
+
+ // Sensors
+ private val locationObserver: Observer<Location> = Observer { location ->
+ measureAndPrintTimeMillis("onNewLocation") {
+ mapboxMapView.onNewLocation(location)
+ }
+ }
+
+ override fun onExplanationNeeded(permissionsToExplain: MutableList<String>?) {
+ Toast.makeText(this, R.string.user_location_permission_explanation, Toast.LENGTH_LONG).show()
+ }
+
+ override fun onPermissionResult(granted: Boolean) {
+ if (granted) {
+ createMapboxMapView()
+ } else {
+ Toast.makeText(this, R.string.user_location_permission_not_granted, Toast.LENGTH_LONG).show()
+ }
+ }
+}
+
+/**
+ * Executes the given [block] and returns elapsed time in milliseconds.
+ */
+public inline fun <T> measureAndPrintTimeMillis(blockName: String, block: () -> T): T {
+ val start = SystemClock.elapsedRealtime()
+ val t = block()
+ val elapsedTime = SystemClock.elapsedRealtime() - start
+ Log.d("MapExample", "It took $elapsedTime ms to run [$blockName]")
+ return t
+}
+
diff --git a/mapbox/src/main/java/com/example/mapbox/MainActivityModule.kt b/mapbox/src/main/java/com/example/mapbox/MainActivityModule.kt
new file mode 100644
index 0000000000..eec66ebee3
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/MainActivityModule.kt
@@ -0,0 +1,10 @@
+package com.example.mapbox
+
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+
+@Module
+abstract class MainActivityModule {
+ @ContributesAndroidInjector
+ internal abstract fun mainActivity(): MainActivity
+}
diff --git a/mapbox/src/main/java/com/example/mapbox/MapboxApp.kt b/mapbox/src/main/java/com/example/mapbox/MapboxApp.kt
new file mode 100644
index 0000000000..ded4931802
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/MapboxApp.kt
@@ -0,0 +1,16 @@
+package com.example.mapbox
+
+import dagger.android.AndroidInjector
+import dagger.android.DaggerApplication
+
+class MapboxApp : DaggerApplication() {
+ private val appComponent: AndroidInjector<MapboxApp> by lazy {
+ DaggerAppComponent
+ .builder()
+ .create(this)
+ }
+
+ override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
+ return appComponent
+ }
+} \ No newline at end of file
diff --git a/mapbox/src/main/java/com/example/mapbox/breadcrumb/Breadcrumb.kt b/mapbox/src/main/java/com/example/mapbox/breadcrumb/Breadcrumb.kt
new file mode 100644
index 0000000000..af27cc36b6
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/breadcrumb/Breadcrumb.kt
@@ -0,0 +1,157 @@
+package com.soy.android.maps.breadcrumb
+
+import android.content.res.Resources
+import com.example.mapbox.breadcrumb.ExerciseEngineState
+import com.example.mapbox.ui.MapboxMapView
+import com.mapbox.mapboxsdk.geometry.LatLng
+import com.mapbox.mapboxsdk.location.OnLocationStaleListener
+import com.mapbox.mapboxsdk.maps.MapboxMap
+import com.mapbox.mapboxsdk.maps.Style
+import com.mapbox.mapboxsdk.plugins.annotation.Line
+import com.mapbox.mapboxsdk.plugins.annotation.LineManager
+import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager
+import timber.log.Timber
+
+/**
+ * Note that this is not public API and taken from [com.mapbox.mapboxsdk.location.LocationComponentConstants]. Needed
+ * to be hardcoded to have the line layer below the location indicator
+ */
+private const val LOCATION_INDICATOR_BACKGROUND_LAYER_ID = "mapbox-location-stroke-layer"
+
+class Breadcrumb(
+ mapView: MapboxMapView,
+ private val map: MapboxMap,
+ style: Style
+) : OnLocationStaleListener {
+
+ private val lineManager: LineManager = LineManager(mapView, map, style, LOCATION_INDICATOR_BACKGROUND_LAYER_ID)
+ private val symbolManager: SymbolManager = SymbolManager(mapView, map, style, LOCATION_INDICATOR_BACKGROUND_LAYER_ID)
+ private val resources: Resources
+
+ init {
+ map.locationComponent.addOnLocationStaleListener(this)
+ resources = mapView.resources
+ }
+
+ /**
+ * Flag that represents whether start symbol is created
+ */
+ private var startSymbolCreated = false
+
+ /**
+ * Holds [LatLng] list of current recording state line. A recording state line is the line which holds the list of
+ * [LatLng] recorded during [Recording] state. When state is [Paused] last recording state line does not receive
+ * updates and when the state is [Recording] after [Paused] state a new line is created and that line is updated
+ * according to [currentRecordingStateLatLngs]
+ */
+ private var currentRecordingStateLatLngs = mutableListOf<LatLng>()
+
+ /**
+ * A recording state line is the line which is created and updated during [Recording] state.
+ *
+ * When state is [Paused] last recording state line does not receive updates.
+ *
+ * [currentRecordingStateLine] is the line which is created either at the beginning of the exercise or when the
+ * state is [Recording] again after last [Paused] state.
+ */
+ private var currentRecordingStateLine: Line? = null
+
+ /**
+ * The [ExerciseEngineState] which belongs to the previous [com.soy.android.maps.livedata.StatefulLocation]
+ */
+ private var previousExerciseEngineState: ExerciseEngineState? = null
+
+ private var fromStaleState = false
+
+ private var isMapViewVisible = true
+
+ internal fun onNewLocation(latLng: LatLng, exerciseEngineState: ExerciseEngineState?) {
+ if (!startSymbolCreated) {
+ // We create a start symbol when the exercise is started
+ symbolManager.addStartExerciseSymbol(latLng)
+ startSymbolCreated = true
+ previousExerciseEngineState = exerciseEngineState
+ return
+ }
+ when {
+ exerciseRecording(exerciseEngineState) -> {
+ if (fromStaleState) {
+ fromStaleState = false
+ map.locationComponent.addOnLocationStaleListener(this)
+ lineManager.createStaleStateLine(listOf(currentRecordingStateLatLngs.last(), latLng))
+ // clear the recording state latlng list and add the start point for the new line
+ currentRecordingStateLatLngs.clear()
+ currentRecordingStateLatLngs.add(latLng)
+ } else {
+ currentRecordingStateLatLngs.add(latLng)
+ createOrUpdateRecordingLine()
+ }
+ }
+ exercisePaused(exerciseEngineState) -> {
+ // add the end point for currentRecordingStateLine
+ currentRecordingStateLatLngs.add(latLng)
+ createOrUpdateRecordingLine()
+ // add the start point of the pause line
+ }
+ exerciseResumed(exerciseEngineState) -> {
+ // add the end point of the pause line
+ // create the pause line
+ lineManager.createPausedStateLine(listOf(currentRecordingStateLatLngs.last(), latLng))
+ Timber.d("Pause state line is created")
+ // after we create the pause line we clear pauseLinePoints for next possible pause line
+ // clear the recording state latlng list and add the start point for the new line
+ currentRecordingStateLatLngs.clear()
+ currentRecordingStateLatLngs.add(latLng)
+ createOrUpdateRecordingLine()
+ }
+ }
+ previousExerciseEngineState = exerciseEngineState
+ }
+
+ private fun createOrUpdateRecordingLine() {
+ currentRecordingStateLine?.let {
+ // we update the latlng list for currentRecordingStateLine
+ it.latLngs = currentRecordingStateLatLngs
+ // We update the currentRecordingStateLine only when the mapview is visible
+ if (isMapViewVisible) {
+ lineManager.update(it)
+ Timber.d("Recording state line is updated")
+ }
+ } ?: run {
+ if (currentRecordingStateLatLngs.size > 1) {
+ Timber.d("Recording state line is created")
+ currentRecordingStateLine = lineManager.createRecordingStateLine(currentRecordingStateLatLngs)
+ }
+ }
+ }
+
+ private fun exerciseResumed(exerciseEngineState: ExerciseEngineState?) =
+ previousExerciseEngineState == ExerciseEngineState.Paused && exerciseEngineState == ExerciseEngineState.Recording
+
+ private fun exercisePaused(exerciseEngineState: ExerciseEngineState?) =
+ previousExerciseEngineState == ExerciseEngineState.Recording && exerciseEngineState == ExerciseEngineState.Paused
+
+ private fun exerciseRecording(exerciseEngineState: ExerciseEngineState?) =
+ previousExerciseEngineState == ExerciseEngineState.Recording && exerciseEngineState == ExerciseEngineState.Recording
+
+ internal fun onDestroy() {
+ lineManager.onDestroy()
+ symbolManager.onDestroy()
+ }
+
+ internal fun onResume() {
+ isMapViewVisible = true
+ createOrUpdateRecordingLine()
+ }
+
+ internal fun onStop() {
+ isMapViewVisible = false
+ }
+
+ override fun onStaleStateChange(isStale: Boolean) {
+ if (isStale) {
+ map.locationComponent.removeOnLocationStaleListener(this)
+ fromStaleState = isStale
+ }
+ }
+} \ No newline at end of file
diff --git a/mapbox/src/main/java/com/example/mapbox/breadcrumb/ExerciseEngineState.kt b/mapbox/src/main/java/com/example/mapbox/breadcrumb/ExerciseEngineState.kt
new file mode 100644
index 0000000000..1d78bb7035
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/breadcrumb/ExerciseEngineState.kt
@@ -0,0 +1,6 @@
+package com.example.mapbox.breadcrumb
+
+enum class ExerciseEngineState {
+ Paused,
+ Recording
+} \ No newline at end of file
diff --git a/mapbox/src/main/java/com/example/mapbox/compass/WassCompassEngine.kt b/mapbox/src/main/java/com/example/mapbox/compass/WassCompassEngine.kt
new file mode 100644
index 0000000000..6795ea68c4
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/compass/WassCompassEngine.kt
@@ -0,0 +1,48 @@
+package com.soy.android.maps.compass
+
+import android.hardware.SensorManager.SENSOR_STATUS_ACCURACY_HIGH
+import androidx.lifecycle.Observer
+import com.example.mapbox.livedata.HeadingSensorLiveData
+import com.mapbox.mapboxsdk.location.CompassEngine
+import com.mapbox.mapboxsdk.location.CompassListener
+
+class WassCompassEngine(
+ private val headingSensorLiveData: HeadingSensorLiveData?
+) : CompassEngine {
+
+ private val compassListeners = mutableListOf<CompassListener>()
+
+ private var lastHeading: Float = 0.0f
+
+ private val headingObserver: Observer<Float> = Observer {
+ lastHeading = Math.toDegrees(it.toDouble()).toFloat()
+ notifyCompassChangeListeners(lastHeading)
+ }
+
+ /**
+ * Always returns [SENSOR_STATUS_ACCURACY_HIGH] and should not mean anything in this context
+ */
+ override fun getLastAccuracySensorStatus() = SENSOR_STATUS_ACCURACY_HIGH
+
+ override fun addCompassListener(compassListener: CompassListener) {
+ compassListeners.add(compassListener)
+ }
+
+ override fun removeCompassListener(compassListener: CompassListener) {
+ compassListeners.remove(compassListener)
+ }
+
+ override fun getLastHeading() = lastHeading
+
+ fun requestUpdates() = headingSensorLiveData?.observeForever(headingObserver)
+
+ fun removeUpdates() = headingSensorLiveData?.removeObserver(headingObserver)
+
+ private fun notifyCompassChangeListeners(heading: Float) {
+ lastHeading = heading.apply {
+ for (compassListener in compassListeners) {
+ compassListener.onCompassChanged(this)
+ }
+ }
+ }
+}
diff --git a/mapbox/src/main/java/com/example/mapbox/di/AppComponent.kt b/mapbox/src/main/java/com/example/mapbox/di/AppComponent.kt
new file mode 100644
index 0000000000..039ca746c0
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/di/AppComponent.kt
@@ -0,0 +1,19 @@
+import com.example.mapbox.MainActivityModule
+import com.example.mapbox.MapboxApp
+import dagger.Component
+import dagger.android.AndroidInjector
+import dagger.android.support.AndroidSupportInjectionModule
+import javax.inject.Singleton
+
+/**
+ * Application component refers to application level modules only
+ */
+@Singleton
+@Component(modules = [
+ AndroidSupportInjectionModule::class,
+ MainActivityModule::class
+])
+interface AppComponent : AndroidInjector<MapboxApp> {
+ @Component.Builder
+ abstract class Builder : AndroidInjector.Builder<MapboxApp>()
+} \ No newline at end of file
diff --git a/mapbox/src/main/java/com/example/mapbox/extensions/AnnotationsExtensions.kt b/mapbox/src/main/java/com/example/mapbox/extensions/AnnotationsExtensions.kt
new file mode 100644
index 0000000000..be4f09d9ff
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/extensions/AnnotationsExtensions.kt
@@ -0,0 +1,48 @@
+package com.soy.android.maps.breadcrumb
+
+import com.example.mapbox.ui.PAUSE_LINE_PATTERN
+import com.example.mapbox.ui.START_SYMBOL_ICON_ID
+import com.mapbox.mapboxsdk.geometry.LatLng
+import com.mapbox.mapboxsdk.plugins.annotation.*
+import com.mapbox.mapboxsdk.style.layers.Property
+
+private const val MAP_LINE_WIDTH = 4f // In pixels
+private const val COLOR_MAP_LINE_REGULAR = "#FF5640"
+private const val COLOR_MAP_LINE_PAUSE = "#00000000"
+private const val MAP_LINE_PAUSE_OPACITY = 0.2f
+
+internal fun SymbolManager.addStartExerciseSymbol(latLng: LatLng) {
+ val option = SymbolOptions()
+ .withLatLng(latLng)
+ .withIconImage(START_SYMBOL_ICON_ID)
+ this.create(option)
+}
+
+internal fun LineManager.createRecordingStateLine(recordingStateLatLngs: List<LatLng>): Line {
+ lineCap = Property.LINE_CAP_BUTT
+ val lineOptions = LineOptions()
+ .withLatLngs(recordingStateLatLngs)
+ .withLineJoin(Property.LINE_JOIN_ROUND)
+ .withLineColor(COLOR_MAP_LINE_REGULAR)
+ .withLineWidth(MAP_LINE_WIDTH)
+ return this.create(lineOptions)
+}
+
+internal fun LineManager.createPausedStateLine(startEndPoints: List<LatLng>): Line {
+ val lineOptions = LineOptions()
+ .withLatLngs(startEndPoints)
+ .withLineJoin(Property.LINE_JOIN_ROUND)
+ .withLineColor(COLOR_MAP_LINE_PAUSE)
+ .withLineWidth(MAP_LINE_WIDTH)
+ .withLinePattern(PAUSE_LINE_PATTERN)
+ return this.create(lineOptions)
+}
+
+internal fun LineManager.createStaleStateLine(startEndPoints: List<LatLng>): Line {
+ val lineOptions = LineOptions()
+ .withLatLngs(startEndPoints)
+ .withLineJoin(Property.LINE_JOIN_ROUND)
+ .withLineColor(COLOR_MAP_LINE_REGULAR)
+ .withLineWidth(MAP_LINE_WIDTH)
+ return this.create(lineOptions)
+} \ No newline at end of file
diff --git a/mapbox/src/main/java/com/example/mapbox/extensions/LocationExtensions.kt b/mapbox/src/main/java/com/example/mapbox/extensions/LocationExtensions.kt
new file mode 100644
index 0000000000..67bebf7504
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/extensions/LocationExtensions.kt
@@ -0,0 +1,8 @@
+package com.example.mapbox.extensions
+
+import android.location.Location
+import com.mapbox.mapboxsdk.geometry.LatLng
+
+fun Location.latLong(): LatLng {
+ return LatLng(latitude, longitude)
+} \ No newline at end of file
diff --git a/mapbox/src/main/java/com/example/mapbox/extensions/MapboxMapExtensions.kt b/mapbox/src/main/java/com/example/mapbox/extensions/MapboxMapExtensions.kt
new file mode 100644
index 0000000000..eb863f9f64
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/extensions/MapboxMapExtensions.kt
@@ -0,0 +1,22 @@
+package com.soy.android.maps.extensions
+
+import com.mapbox.mapboxsdk.location.modes.CameraMode
+import com.mapbox.mapboxsdk.maps.MapboxMap
+import com.mapbox.mapboxsdk.maps.Style
+import kotlinx.coroutines.suspendCancellableCoroutine
+import timber.log.Timber
+import kotlin.coroutines.resume
+
+fun MapboxMap.isCameraInTrackingMode() = getActivatedLocationComponent()?.run {
+ cameraMode == CameraMode.TRACKING_COMPASS ||
+ cameraMode == CameraMode.TRACKING ||
+ cameraMode == CameraMode.TRACKING_GPS ||
+ cameraMode == CameraMode.TRACKING_GPS_NORTH
+}
+
+fun MapboxMap.getActivatedLocationComponent() = locationComponent.takeIf {
+ it.isLocationComponentEnabled
+} ?: run {
+ Timber.w("Calling location component, but it is not enabled.")
+ null
+}
diff --git a/mapbox/src/main/java/com/example/mapbox/extensions/ResourceExtensions.kt b/mapbox/src/main/java/com/example/mapbox/extensions/ResourceExtensions.kt
new file mode 100644
index 0000000000..785ed32840
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/extensions/ResourceExtensions.kt
@@ -0,0 +1,25 @@
+package com.example.mapbox.extensions
+
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import androidx.annotation.DrawableRes
+
+fun Resources.getBitmapFromDrawable(@DrawableRes drawableResId: Int): Bitmap {
+ return getDrawable(drawableResId, null).getBitmapFromDrawable()
+}
+
+fun Drawable.getBitmapFromDrawable(): Bitmap {
+ return if (this is BitmapDrawable) {
+ bitmap
+ } else {
+ val bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888)
+ Canvas(bitmap).let {
+ setBounds(0, 0, it.width, it.height)
+ draw(it)
+ bitmap
+ }
+ }
+} \ No newline at end of file
diff --git a/mapbox/src/main/java/com/example/mapbox/livedata/HeadingSensorLiveData.kt b/mapbox/src/main/java/com/example/mapbox/livedata/HeadingSensorLiveData.kt
new file mode 100644
index 0000000000..4acbfb754a
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/livedata/HeadingSensorLiveData.kt
@@ -0,0 +1,33 @@
+package com.example.mapbox.livedata
+
+import androidx.lifecycle.LiveData
+import com.example.mapbox.mockdata.MockHeadingSensor
+import kotlinx.coroutines.*
+import javax.inject.Inject
+
+private const val GPS_FIX_INTERVAL_MILLISEC = 1000L
+
+class HeadingSensorLiveData @Inject constructor(
+ private val mockHeadingSensor: MockHeadingSensor
+) : LiveData<Float>() {
+
+ private val job = Job()
+ private val backgroundScope = CoroutineScope(Dispatchers.Default + job)
+
+ override fun onActive() {
+ super.onActive()
+ backgroundScope.launch {
+ while(true) {
+ delay(GPS_FIX_INTERVAL_MILLISEC)
+ withContext(Dispatchers.Main) {
+ value = mockHeadingSensor.generateNextValue()
+ }
+ }
+ }
+ }
+
+ override fun onInactive() {
+ job.cancel()
+ super.onInactive()
+ }
+}
diff --git a/mapbox/src/main/java/com/example/mapbox/livedata/LocationSensorLiveData.kt b/mapbox/src/main/java/com/example/mapbox/livedata/LocationSensorLiveData.kt
new file mode 100644
index 0000000000..c58f9d39e9
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/livedata/LocationSensorLiveData.kt
@@ -0,0 +1,35 @@
+package com.soy.android.maps.livedata
+
+import android.location.Location
+import androidx.lifecycle.LiveData
+import com.asoy.wass.sdk.android.sensor.MockLocationSensor
+import kotlinx.coroutines.*
+import javax.inject.Inject
+
+private const val HEADING_INTERVAL_MILLISEC = 500L
+
+class LocationSensorLiveData
+@Inject constructor(
+ private val mockLocationSensor: MockLocationSensor
+) : LiveData<Location>() {
+
+ private val job = Job()
+ private val backgroundScope = CoroutineScope(Dispatchers.Default + job)
+
+ override fun onActive() {
+ super.onActive()
+ backgroundScope.launch {
+ while (true) {
+ delay(HEADING_INTERVAL_MILLISEC)
+ withContext(Dispatchers.Main) {
+ value = mockLocationSensor.generateNextValue()
+ }
+ }
+ }
+ }
+
+ override fun onInactive() {
+ job.cancel()
+ super.onInactive()
+ }
+}
diff --git a/mapbox/src/main/java/com/example/mapbox/livedata/LocationWithHeadingLiveData.kt b/mapbox/src/main/java/com/example/mapbox/livedata/LocationWithHeadingLiveData.kt
new file mode 100644
index 0000000000..2d09e9bfd5
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/livedata/LocationWithHeadingLiveData.kt
@@ -0,0 +1,30 @@
+package com.example.mapbox.livedata
+
+import android.location.Location
+import androidx.lifecycle.MediatorLiveData
+import com.soy.android.maps.livedata.LocationSensorLiveData
+import javax.inject.Inject
+
+/**
+ * [MediatorLiveData] wrapper used to expose the [AndroidLocation].
+ *
+ * The value is mediated based on the last recorded values of [LocationSensorLiveData]
+ * and [HeadingSensorLiveData], and each time [LocationSensorLiveData] emits a value
+ * a new [AndroidLocation] value is emitted by this mediator live data. Note that if
+ */
+class LocationWithHeadingLiveData
+@Inject constructor(
+ headingSensorLiveData: HeadingSensorLiveData,
+ locationSensorLiveData: LocationSensorLiveData
+) : MediatorLiveData<Location>() {
+ init {
+ addSource(locationSensorLiveData) {
+ headingSensorLiveData.value?.let {heading ->
+ // Convert radian to degree
+ it.bearing = Math.toDegrees(heading.toDouble()).toFloat()
+ value = it
+ }
+ }
+ addSource(headingSensorLiveData) {}
+ }
+}
diff --git a/mapbox/src/main/java/com/example/mapbox/livedata/MapViewSensors.kt b/mapbox/src/main/java/com/example/mapbox/livedata/MapViewSensors.kt
new file mode 100644
index 0000000000..8b56fff3f6
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/livedata/MapViewSensors.kt
@@ -0,0 +1,37 @@
+package com.soy.android.maps.livedata
+
+import android.location.Location
+import androidx.lifecycle.Observer
+import com.example.mapbox.livedata.HeadingSensorLiveData
+import com.example.mapbox.livedata.LocationWithHeadingLiveData
+import javax.inject.Inject
+
+class MapViewSensors
+@Inject constructor(
+ val locationLiveData: LocationWithHeadingLiveData,
+ val headingLiveData: HeadingSensorLiveData
+) {
+ fun requestUpdates(
+ locationObserver: Observer<Location>? = null,
+ headingObserver: Observer<Float>? = null
+ ) {
+ locationObserver?.let {
+ locationLiveData.observeForever(it)
+ }
+ headingObserver?.let {
+ headingLiveData.observeForever(it)
+ }
+ }
+
+ fun removeUpdates(
+ locationObserver: Observer<Location>? = null,
+ headingObserver: Observer<Float>? = null
+ ) {
+ locationObserver?.let {
+ locationLiveData.removeObserver(it)
+ }
+ headingObserver?.let {
+ headingLiveData.removeObserver(it)
+ }
+ }
+}
diff --git a/mapbox/src/main/java/com/example/mapbox/mockdata/MockHeadingSensor.kt b/mapbox/src/main/java/com/example/mapbox/mockdata/MockHeadingSensor.kt
new file mode 100644
index 0000000000..9029d89f29
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/mockdata/MockHeadingSensor.kt
@@ -0,0 +1,18 @@
+package com.example.mapbox.mockdata
+
+import javax.inject.Inject
+
+class MockHeadingSensor
+@Inject constructor() {
+
+ private var heading: Float = 0f
+
+ fun generateNextValue(): Float {
+ // Rotate 90deg in 10 seconds
+ heading += 0.1570796326794f
+ if (heading >= 2.0f * Math.PI.toFloat()) {
+ heading = 0.0f
+ }
+ return heading
+ }
+}
diff --git a/mapbox/src/main/java/com/example/mapbox/mockdata/MockLocationSensor.kt b/mapbox/src/main/java/com/example/mapbox/mockdata/MockLocationSensor.kt
new file mode 100644
index 0000000000..26d97ba450
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/mockdata/MockLocationSensor.kt
@@ -0,0 +1,31 @@
+package com.asoy.wass.sdk.android.sensor
+
+import android.location.Location
+import android.location.LocationManager
+import javax.inject.Inject
+
+class MockLocationSensor
+@Inject constructor() {
+
+ private var currentPosition = 0
+ private var step = 1
+
+ fun generateNextValue(): Location {
+ val lat = lats[currentPosition]
+ val long = longs[currentPosition]
+ currentPosition += step
+ if (currentPosition >= lats.size) {
+ step = -1
+ currentPosition = lats.size - 1
+ } else if (currentPosition <= 0) {
+ step = 1
+ currentPosition = 0
+ }
+ return Location(LocationManager.GPS_PROVIDER).also { location ->
+ location.accuracy = 0.0f
+ location.latitude = lat
+ location.longitude = long
+ location.altitude = 0.0
+ }
+ }
+}
diff --git a/mapbox/src/main/java/com/example/mapbox/mockdata/MockLocations.kt b/mapbox/src/main/java/com/example/mapbox/mockdata/MockLocations.kt
new file mode 100644
index 0000000000..4d1c4fe6dc
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/mockdata/MockLocations.kt
@@ -0,0 +1,661 @@
+package com.asoy.wass.sdk.android.sensor
+
+// This is just a list of extracted latitudes and longitudes from a real exercise
+
+internal val lats = listOf(60.22488, 60.22492, 60.22495, 60.22497, 60.225, 60.22502, 60.22505,
+ 60.22507, 60.22509, 60.22513, 60.22515, 60.22518, 60.2252, 60.22523, 60.22525, 60.22527,
+ 60.22529, 60.22532, 60.22534, 60.22536, 60.22538, 60.22541, 60.22552, 60.22563, 60.22571,
+ 60.22576, 60.22579, 60.22587, 60.22597, 60.226, 60.2261, 60.22612, 60.22615, 60.22618,
+ 60.22622, 60.22627, 60.22629, 60.22631, 60.22633, 60.22635, 60.22637, 60.22639, 60.22642,
+ 60.22644, 60.22649, 60.22653, 60.2266, 60.22668, 60.22672, 60.22675, 60.22683, 60.22686,
+ 60.22688, 60.22693, 60.22694, 60.22702, 60.22707, 60.22711, 60.22713, 60.22714, 60.22716,
+ 60.22717, 60.22718, 60.22719, 60.2272, 60.22722, 60.22723, 60.22724, 60.22724, 60.22725,
+ 60.22727, 60.22729, 60.2273, 60.22732, 60.22733, 60.22734, 60.22738, 60.2274, 60.22741,
+ 60.22745, 60.22747, 60.22749, 60.2275, 60.22752, 60.22757, 60.22761, 60.22763, 60.22765,
+ 60.22767, 60.22768, 60.2277, 60.22771, 60.22772, 60.22773, 60.22775, 60.2278, 60.22782,
+ 60.22782, 60.22782, 60.22783, 60.22782, 60.22782, 60.22782, 60.2278, 60.22778, 60.22778,
+ 60.22777, 60.22778, 60.22778, 60.22778, 60.22779, 60.22779, 60.2278, 60.2278, 60.22783,
+ 60.22783, 60.22784, 60.22784, 60.22784, 60.22784, 60.22784, 60.22784, 60.22785, 60.22787,
+ 60.22788, 60.22788, 60.22788, 60.22788, 60.22787, 60.22788, 60.22788, 60.22789, 60.22792,
+ 60.22795, 60.22796, 60.22795, 60.22793, 60.22795, 60.22795, 60.22794, 60.22793, 60.22791,
+ 60.22789, 60.22787, 60.22786, 60.22784, 60.22783, 60.2278, 60.22779, 60.22775, 60.22774,
+ 60.22773, 60.22772, 60.22771, 60.2277, 60.22768, 60.22765, 60.22764, 60.22761, 60.2276,
+ 60.2276, 60.2276, 60.22759, 60.22758, 60.22757, 60.22756, 60.22756, 60.22755, 60.22755,
+ 60.22754, 60.22753, 60.22752, 60.22752, 60.22752, 60.22753, 60.22754, 60.22755, 60.22756,
+ 60.22756, 60.22756, 60.22756, 60.22757, 60.22758, 60.22759, 60.22761, 60.22763, 60.22765,
+ 60.22766, 60.22767, 60.22768, 60.22769, 60.22769, 60.22771, 60.22773, 60.22774, 60.22776,
+ 60.22777, 60.2278, 60.22782, 60.22783, 60.22785, 60.22786, 60.22788, 60.2279, 60.22792,
+ 60.22793, 60.22795, 60.22796, 60.22798, 60.22799, 60.22801, 60.22802, 60.22803, 60.22804,
+ 60.22806, 60.22807, 60.22808, 60.22809, 60.2281, 60.2281, 60.22811, 60.22811, 60.22812,
+ 60.22813, 60.22813, 60.22813, 60.22815, 60.22817, 60.22818, 60.22818, 60.22819, 60.2282,
+ 60.22821, 60.22821, 60.22821, 60.22822, 60.22823, 60.22823, 60.22824, 60.22824, 60.22824,
+ 60.22824, 60.22825, 60.22825, 60.22826, 60.22826, 60.22827, 60.22827, 60.22827, 60.22827,
+ 60.22826, 60.22826, 60.22825, 60.22825, 60.22825, 60.22825, 60.22825, 60.22825, 60.22825,
+ 60.22825, 60.22825, 60.22825, 60.22825, 60.22826, 60.22826, 60.22826, 60.22826, 60.22826,
+ 60.22826, 60.22826, 60.22826, 60.22826, 60.22826, 60.22825, 60.22825, 60.22825, 60.22825,
+ 60.22825, 60.22824, 60.22825, 60.22825, 60.22825, 60.22825, 60.22825, 60.22826, 60.22826,
+ 60.22827, 60.22827, 60.22828, 60.22829, 60.22831, 60.22832, 60.22833, 60.22834, 60.22835,
+ 60.22838, 60.22839, 60.2284, 60.22841, 60.22843, 60.22844, 60.22845, 60.22846, 60.22848,
+ 60.22849, 60.2285, 60.22851, 60.22851, 60.22852, 60.22853, 60.22854, 60.22854, 60.2285,
+ 60.22847, 60.22845, 60.22843, 60.2284, 60.22838, 60.22835, 60.22832, 60.22829, 60.22826,
+ 60.22823, 60.2282, 60.22809, 60.22799, 60.2279, 60.22787, 60.22784, 60.22781, 60.22779,
+ 60.22776, 60.22774, 60.22771, 60.22768, 60.22765, 60.22763, 60.2276, 60.22757, 60.22755,
+ 60.22752, 60.22747, 60.22744, 60.22741, 60.22738, 60.22736, 60.22733, 60.2273, 60.2272,
+ 60.2271, 60.22699, 60.2269, 60.2268, 60.22669, 60.22662, 60.22654, 60.22652, 60.22648,
+ 60.22646, 60.22645, 60.22642, 60.22639, 60.22637, 60.22636, 60.22627, 60.22618, 60.2261,
+ 60.22602, 60.22594, 60.22591, 60.22588, 60.22585, 60.22583, 60.2258, 60.22578, 60.22575,
+ 60.22573, 60.22571, 60.2257, 60.22568, 60.22567, 60.22566, 60.22566, 60.22568, 60.22572,
+ 60.22573, 60.22576, 60.22579, 60.22582, 60.22585, 60.22587, 60.2259, 60.22592, 60.22594,
+ 60.22595, 60.22596, 60.22597, 60.22599, 60.22601, 60.22604, 60.22605, 60.22607, 60.22608,
+ 60.2261, 60.22611, 60.22613, 60.22614, 60.22616, 60.22619, 60.22622, 60.22624, 60.22625,
+ 60.22626, 60.22629, 60.22633, 60.22635, 60.22637, 60.2264, 60.22643, 60.22647, 60.22649,
+ 60.22651, 60.22652, 60.22654, 60.22655, 60.22658, 60.22659, 60.22661, 60.22662, 60.22665,
+ 60.22666, 60.22668, 60.2267, 60.22671, 60.22673, 60.22675, 60.22677, 60.2268, 60.22682,
+ 60.22689, 60.22691, 60.22694, 60.22696, 60.22699, 60.22702, 60.22704, 60.22706, 60.22709,
+ 60.22712, 60.22714, 60.22722, 60.22727, 60.22732, 60.22736, 60.22739, 60.22742, 60.22744,
+ 60.22748, 60.22751, 60.22754, 60.22756, 60.22759, 60.22762, 60.22765, 60.22767, 60.2277,
+ 60.22772, 60.22774, 60.22776, 60.22778, 60.2278, 60.22782, 60.22784, 60.22786, 60.22787,
+ 60.22789, 60.22791, 60.22793, 60.22795, 60.22797, 60.228, 60.22802, 60.22804, 60.22807,
+ 60.22811, 60.22814, 60.22818, 60.2282, 60.22823, 60.22825, 60.22827, 60.22829, 60.22831,
+ 60.22834, 60.22837, 60.22839, 60.22841, 60.22844, 60.22845, 60.22847, 60.22849, 60.22855,
+ 60.22858, 60.2286, 60.22863, 60.22866, 60.22869, 60.22872, 60.22875, 60.22877, 60.22881,
+ 60.22884, 60.22886, 60.22888, 60.22892, 60.22895, 60.22897, 60.22899, 60.22903, 60.22906,
+ 60.22909, 60.22913, 60.22917, 60.22922, 60.22925, 60.22928, 60.22931, 60.22935, 60.22938,
+ 60.22942, 60.22945, 60.22948, 60.22951, 60.22954, 60.22957, 60.2296, 60.22962, 60.22965,
+ 60.22968, 60.22978, 60.22986, 60.22987, 60.22989, 60.2299, 60.22992, 60.22995, 60.22997,
+ 60.22999, 60.23001, 60.23003, 60.23005, 60.23011, 60.23014, 60.2302, 60.23029, 60.23033,
+ 60.23038, 60.23042, 60.23043, 60.23045, 60.23046, 60.23045, 60.23043, 60.23043, 60.2304,
+ 60.23038, 60.23034, 60.2303, 60.23029, 60.23025, 60.2302, 60.23015, 60.23014, 60.23008,
+ 60.23001, 60.22994, 60.22987, 60.22982, 60.22978, 60.22976, 60.22973, 60.22969, 60.22962,
+ 60.22955, 60.22945, 60.22938, 60.22929, 60.22926, 60.22923, 60.22921, 60.22919, 60.22917,
+ 60.22916, 60.22913, 60.22912, 60.2291, 60.22909, 60.22905, 60.22899, 60.22893, 60.22889,
+ 60.22886, 60.22882, 60.22878, 60.22873, 60.22869, 60.22865, 60.22863, 60.22863, 60.22862,
+ 60.22862, 60.22861, 60.2286, 60.22859, 60.22858, 60.22858, 60.22858, 60.22858, 60.22858,
+ 60.22858, 60.22858, 60.22858, 60.22858, 60.22858, 60.22859, 60.22859, 60.2286, 60.2286,
+ 60.2286, 60.2286, 60.22861, 60.2286, 60.22859, 60.22858, 60.22856, 60.22855, 60.22853,
+ 60.22852, 60.22851, 60.2285, 60.22848, 60.22841, 60.22839, 60.22836, 60.22834, 60.22832,
+ 60.22829, 60.22827, 60.22824, 60.22822, 60.2282, 60.22818, 60.22815, 60.22813, 60.22811,
+ 60.22808, 60.22805, 60.22802, 60.228, 60.22797, 60.22794, 60.22791, 60.22789, 60.22787,
+ 60.22784, 60.22782, 60.22779, 60.22777, 60.22774, 60.22771, 60.22769, 60.22766, 60.22764,
+ 60.22761, 60.22759, 60.22757, 60.22754, 60.22752, 60.2275, 60.22747, 60.22744, 60.22742,
+ 60.2274, 60.22738, 60.22736, 60.22734, 60.22732, 60.22729, 60.22727, 60.22725, 60.22722,
+ 60.22719, 60.22716, 60.22714, 60.22712, 60.22709, 60.22707, 60.22704, 60.22702, 60.22699,
+ 60.22697, 60.22694, 60.22692, 60.22689, 60.22687, 60.22684, 60.22682, 60.2268, 60.22677,
+ 60.22675, 60.22673, 60.2267, 60.22668, 60.22666, 60.22663, 60.22661, 60.22659, 60.22656,
+ 60.22654, 60.22651, 60.22649, 60.22647, 60.22645, 60.22642, 60.2264, 60.22638, 60.22635,
+ 60.22633, 60.22631, 60.22629, 60.22627, 60.22624, 60.22622, 60.2262, 60.22618, 60.22616,
+ 60.22614, 60.22612, 60.22606, 60.22601, 60.22599, 60.22598, 60.22597, 60.22595, 60.22595,
+ 60.22594, 60.22592, 60.22591, 60.2259, 60.22589, 60.22588, 60.22586, 60.22585, 60.22582,
+ 60.22581, 60.2258, 60.22578, 60.22578, 60.22576, 60.22575, 60.22574, 60.22573, 60.22571,
+ 60.2257, 60.22569, 60.22567, 60.22566, 60.22564, 60.22563, 60.22562, 60.22561, 60.2256,
+ 60.22558, 60.22557, 60.22555, 60.22554, 60.22552, 60.2255, 60.22548, 60.22547, 60.22546,
+ 60.22545, 60.22544, 60.22543, 60.22541, 60.22541, 60.2254, 60.22539, 60.22538, 60.22537,
+ 60.22536, 60.22535, 60.22534, 60.22532, 60.22532, 60.22531, 60.2253, 60.22528, 60.22527,
+ 60.22525, 60.22524, 60.22523, 60.22521, 60.2252, 60.22518, 60.22517, 60.22516, 60.22515,
+ 60.22513, 60.22512, 60.22511, 60.2251, 60.2251, 60.22509, 60.22509, 60.22508, 60.22507,
+ 60.22507, 60.22507, 60.22507, 60.22507, 60.22507, 60.22506, 60.22506, 60.22505, 60.22505,
+ 60.22504, 60.22503, 60.22503, 60.22502, 60.22502, 60.22501, 60.22501, 60.225, 60.225,
+ 60.225, 60.225, 60.22499, 60.22499, 60.22497, 60.22496, 60.22496, 60.22496, 60.22496,
+ 60.22496, 60.22495, 60.22495, 60.22493, 60.22491, 60.22491, 60.22491, 60.22491, 60.22491,
+ 60.22492, 60.22492, 60.22492, 60.22492, 60.22492, 60.22491, 60.2249, 60.22489, 60.22489,
+ 60.22488, 60.22488, 60.22488, 60.22486, 60.22485, 60.22484, 60.22484, 60.22483, 60.2248,
+ 60.22478, 60.22477, 60.22477, 60.22477, 60.22478, 60.22481, 60.22482, 60.22485, 60.22487,
+ 60.22488, 60.22489, 60.22489, 60.2249, 60.22491, 60.22492, 60.22492, 60.22493, 60.22494,
+ 60.22495, 60.22496, 60.22498, 60.22499, 60.22499, 60.225, 60.22501, 60.22501, 60.22501,
+ 60.22501, 60.22501, 60.22501, 60.22502, 60.22502, 60.22504, 60.22504, 60.22505, 60.22508,
+ 60.22512, 60.22513, 60.22517, 60.22523, 60.22529, 60.22532, 60.22535, 60.22535, 60.22536,
+ 60.22536, 60.22538, 60.2254, 60.22543, 60.22545, 60.22548, 60.22551, 60.22551, 60.22548,
+ 60.22547, 60.22547, 60.22546, 60.22546, 60.22544, 60.22543, 60.22542, 60.22541, 60.22539,
+ 60.22538, 60.22536, 60.22535, 60.22528, 60.22521, 60.22513, 60.22509, 60.22506, 60.22504,
+ 60.22502, 60.22499, 60.22496, 60.22494, 60.22491, 60.22489, 60.22487, 60.22484, 60.22481,
+ 60.22479, 60.22476, 60.22473, 60.22471, 60.22468, 60.22466, 60.22463, 60.22461, 60.22458,
+ 60.22456, 60.22453, 60.2245, 60.22448, 60.22445, 60.22443, 60.2244, 60.22438, 60.22435,
+ 60.22433, 60.2243, 60.22428, 60.22425, 60.22423, 60.2242, 60.22418, 60.22416, 60.22414,
+ 60.22412, 60.22409, 60.22407, 60.22405, 60.22402, 60.22401, 60.22398, 60.22396, 60.22392,
+ 60.2239, 60.22387, 60.22386, 60.22383, 60.22382, 60.22384, 60.22385, 60.22382, 60.22383,
+ 60.22383, 60.22383, 60.22383, 60.22382, 60.2238, 60.2238, 60.22379, 60.22379, 60.2238,
+ 60.2238, 60.2238, 60.22381, 60.22382, 60.22383, 60.22384, 60.22384, 60.22385, 60.22385,
+ 60.22387, 60.22388, 60.2239, 60.22392, 60.22393, 60.22395, 60.22396, 60.22397, 60.22399,
+ 60.22408, 60.22418, 60.22425, 60.22428, 60.22431, 60.22435, 60.22436, 60.22437, 60.22438,
+ 60.22439, 60.2244, 60.22442, 60.22446, 60.22451, 60.22455, 60.22446, 60.22444, 60.22442,
+ 60.22439, 60.22437, 60.22433, 60.22431, 60.22428, 60.22426, 60.22423, 60.22421, 60.22418,
+ 60.22416, 60.22414, 60.22412, 60.22409, 60.22407, 60.22406, 60.22404, 60.22402, 60.22401,
+ 60.22399, 60.22397, 60.22396, 60.22394, 60.22392, 60.22389, 60.22387, 60.22386, 60.22384,
+ 60.22382, 60.2238, 60.22378, 60.22376, 60.22367, 60.22358, 60.2235, 60.22343, 60.22337,
+ 60.2233, 60.22323, 60.22315, 60.22306, 60.22302, 60.22299, 60.22298, 60.22296, 60.22294,
+ 60.22293, 60.22291, 60.22283, 60.22274, 60.22266, 60.22259, 60.22253, 60.22245, 60.22236,
+ 60.22227, 60.22216, 60.22209, 60.22207, 60.22205, 60.222, 60.22198, 60.22196, 60.22194,
+ 60.22192, 60.2219, 60.22188, 60.22185, 60.22182, 60.2218, 60.22177, 60.22175, 60.22173,
+ 60.2217, 60.22168, 60.22166, 60.22164, 60.22162, 60.22159, 60.22157, 60.22155, 60.22152,
+ 60.2215, 60.22148, 60.22145, 60.22143, 60.22141, 60.22139, 60.22136, 60.22134, 60.22131,
+ 60.22129, 60.22126, 60.22124, 60.22122, 60.2212, 60.22119, 60.22114, 60.2211, 60.22105,
+ 60.221, 60.22097, 60.22093, 60.22091, 60.22091, 60.22091, 60.2209, 60.22086, 60.22083,
+ 60.22079, 60.2207, 60.22067, 60.22066, 60.22065, 60.22064, 60.22063, 60.22062, 60.2206,
+ 60.22058, 60.22057, 60.22056, 60.22055, 60.22054, 60.22053, 60.22052, 60.22052, 60.22051,
+ 60.2205, 60.2205, 60.22049, 60.22048, 60.22048, 60.22047, 60.22046, 60.22045, 60.22044,
+ 60.22043, 60.22042, 60.22041, 60.2204, 60.2204, 60.22039, 60.22038, 60.22037, 60.22036,
+ 60.22036, 60.22034, 60.22033, 60.22033, 60.22032, 60.22032, 60.22031, 60.2203, 60.2203,
+ 60.22029, 60.22029, 60.22029, 60.22029, 60.22029, 60.22029, 60.22029, 60.22028, 60.22027,
+ 60.22023, 60.22022, 60.2202, 60.22018, 60.22016, 60.22014, 60.22012, 60.2201, 60.22007,
+ 60.22005, 60.22002, 60.21999, 60.21997, 60.21994, 60.21992, 60.2199, 60.21987, 60.21985,
+ 60.21983, 60.21981, 60.21979, 60.21977, 60.21974, 60.21971, 60.21969, 60.21967, 60.21964,
+ 60.21961, 60.21957, 60.21954, 60.21952, 60.21949, 60.21946, 60.21943, 60.2194, 60.21937,
+ 60.21934, 60.21931, 60.21929, 60.21926, 60.21924, 60.21921, 60.21919, 60.21916, 60.21914,
+ 60.21912, 60.2191, 60.21907, 60.21905, 60.21902, 60.219, 60.21898, 60.21895, 60.21892,
+ 60.2189, 60.21887, 60.21885, 60.21882, 60.2188, 60.21877, 60.21874, 60.21872, 60.21869,
+ 60.21867, 60.21865, 60.21862, 60.2186, 60.21857, 60.21854, 60.21851, 60.21848, 60.21845,
+ 60.21842, 60.21839, 60.21837, 60.21834, 60.21832, 60.21831, 60.21828, 60.21826, 60.21823,
+ 60.21821, 60.21819, 60.2181, 60.21808, 60.21806, 60.21802, 60.21799, 60.21797, 60.21794,
+ 60.21792, 60.21789, 60.21787, 60.21784, 60.21781, 60.21778, 60.21776, 60.21773, 60.21771,
+ 60.21769, 60.21766, 60.21764, 60.21762, 60.2176, 60.21757, 60.21755, 60.21753, 60.21751,
+ 60.21749, 60.21747, 60.21745, 60.21741, 60.21738, 60.21736, 60.21733, 60.2173, 60.21728,
+ 60.21726, 60.21724, 60.21721, 60.21719, 60.21717, 60.21714, 60.21712, 60.21709, 60.21707,
+ 60.21704, 60.21702, 60.21699, 60.21697, 60.21695, 60.21693, 60.2169, 60.21689, 60.21686,
+ 60.21684, 60.21673, 60.21663, 60.21661, 60.21658, 60.21656, 60.21654, 60.2165, 60.21644,
+ 60.21643, 60.21639, 60.21637, 60.21634, 60.21632, 60.2163, 60.21628, 60.21626, 60.21624,
+ 60.21621, 60.21619, 60.21616, 60.21614, 60.21611, 60.21609, 60.21607, 60.21603, 60.216,
+ 60.21598, 60.21596, 60.21593, 60.2159, 60.21586, 60.21583, 60.2158, 60.21577, 60.21575,
+ 60.21572, 60.2157, 60.21567, 60.21563, 60.21561, 60.21558, 60.21556, 60.21553, 60.21546,
+ 60.21544, 60.21541, 60.21539, 60.21536, 60.21534, 60.21532, 60.2153, 60.21529, 60.21528,
+ 60.21527, 60.21525, 60.21524, 60.21523, 60.21522, 60.21521, 60.2152, 60.2152, 60.21519,
+ 60.21519, 60.21518, 60.21518, 60.21518, 60.21518, 60.21518, 60.21517, 60.21516, 60.21516,
+ 60.21515, 60.21514, 60.21514, 60.21514, 60.21513, 60.21513, 60.21513, 60.21512, 60.21513,
+ 60.21513, 60.21513, 60.21514, 60.21514, 60.21515, 60.21516, 60.21516, 60.21518, 60.21519,
+ 60.21524, 60.2153, 60.21537, 60.21541, 60.21543, 60.21547, 60.21547, 60.21548, 60.21549,
+ 60.2155, 60.21551, 60.21552, 60.21553, 60.21553, 60.21553, 60.21552, 60.21552, 60.21551,
+ 60.2155, 60.21549, 60.21549, 60.21548, 60.21547, 60.21546, 60.21544, 60.21543, 60.21541,
+ 60.21539, 60.21538, 60.21536, 60.21534, 60.21532, 60.2153, 60.21528, 60.21525, 60.21523,
+ 60.21521, 60.21519, 60.21517, 60.21515, 60.21512, 60.2151, 60.21507, 60.21505, 60.21503,
+ 60.21501, 60.21499, 60.21497, 60.21495, 60.21493, 60.21491, 60.2149, 60.21488, 60.21486,
+ 60.21485, 60.21483, 60.21482, 60.21481, 60.21479, 60.21478, 60.21477, 60.21475, 60.21475,
+ 60.21474, 60.21473, 60.21472, 60.21471, 60.2147, 60.2147, 60.2147, 60.21469, 60.21469,
+ 60.21469, 60.21468, 60.21468, 60.21468, 60.21468, 60.21468, 60.21468, 60.21468, 60.21468,
+ 60.21467, 60.21467, 60.21467, 60.21467, 60.21466, 60.21466, 60.21466, 60.21465, 60.21464,
+ 60.21464, 60.21463, 60.21463, 60.21462, 60.21462, 60.21461, 60.21461, 60.21461, 60.21461,
+ 60.21461, 60.21461, 60.2146, 60.21459, 60.21458, 60.21458, 60.21457, 60.21457, 60.21456,
+ 60.21456, 60.21456, 60.21455, 60.21455, 60.21454, 60.21454, 60.21453, 60.21453, 60.21452,
+ 60.21452, 60.21451, 60.2145, 60.2145, 60.2145, 60.21449, 60.21449, 60.2145, 60.2145,
+ 60.2145, 60.2145, 60.2145, 60.21451, 60.21452, 60.21452, 60.21452, 60.21452, 60.21453,
+ 60.21453, 60.21453, 60.21453, 60.21453, 60.21453, 60.21452, 60.21452, 60.21452, 60.21451,
+ 60.2145, 60.2145, 60.21449, 60.21447, 60.21446, 60.21444, 60.21443, 60.21442, 60.2144,
+ 60.2144, 60.21438, 60.21437, 60.21437, 60.21436, 60.21436, 60.21435, 60.21435, 60.21435,
+ 60.21434, 60.21433, 60.21433, 60.21432, 60.21431, 60.2143, 60.2143, 60.21429, 60.21429,
+ 60.21428, 60.21426, 60.21425, 60.21424, 60.21423, 60.21422, 60.2142, 60.21419, 60.21418,
+ 60.21416, 60.21415, 60.21414, 60.21412, 60.21411, 60.2141, 60.21408, 60.21407, 60.21405,
+ 60.21404, 60.21403, 60.21401, 60.214, 60.21398, 60.21397, 60.21395, 60.21393, 60.21391,
+ 60.21389, 60.21388, 60.21386, 60.21385, 60.21383, 60.21382, 60.21381, 60.21379, 60.21378,
+ 60.21376, 60.21375, 60.21374, 60.21372, 60.2137, 60.21368, 60.21367, 60.21365, 60.21364,
+ 60.21362, 60.21361, 60.2136, 60.21358, 60.21357, 60.21356, 60.21355, 60.21354, 60.21353,
+ 60.21352, 60.21351, 60.2135, 60.21348, 60.21347, 60.21345, 60.21344, 60.21342, 60.21341,
+ 60.2134, 60.21339, 60.21338, 60.21337, 60.21336, 60.21336, 60.21335, 60.21334, 60.21334,
+ 60.21333, 60.21333, 60.21333, 60.21333, 60.21333, 60.21333, 60.21332, 60.2133, 60.21329,
+ 60.21328, 60.21326, 60.21325, 60.21321, 60.21319, 60.21316, 60.21314, 60.21311, 60.21308,
+ 60.21304, 60.21301, 60.21298, 60.21294, 60.21291, 60.21288, 60.21285, 60.21282, 60.21279,
+ 60.21276, 60.21274, 60.21271, 60.21268, 60.21266, 60.21263, 60.2126, 60.21258, 60.21255,
+ 60.21252, 60.2125, 60.21247, 60.21244, 60.21241, 60.21238, 60.21235, 60.21233, 60.2123,
+ 60.21228, 60.21225, 60.21222, 60.21219, 60.21217, 60.21214, 60.21212, 60.2121, 60.21208,
+ 60.21206, 60.21204, 60.21202, 60.212, 60.21199, 60.21198, 60.21196, 60.21196, 60.21196,
+ 60.21196, 60.21195, 60.21195, 60.21196, 60.21195, 60.21196, 60.21196, 60.21196, 60.21196,
+ 60.21196, 60.21195, 60.21194, 60.21193, 60.21191, 60.2119, 60.21188, 60.21186, 60.21185,
+ 60.21182, 60.2118, 60.21178, 60.21175, 60.21173, 60.21171, 60.21169, 60.21167, 60.21166,
+ 60.21164, 60.21163, 60.21161, 60.21159, 60.21158, 60.21157, 60.21155, 60.21154, 60.21153,
+ 60.21152, 60.21151, 60.2115, 60.21149, 60.21148, 60.21146, 60.21145, 60.21144, 60.21143,
+ 60.21142, 60.21141, 60.21139, 60.21138, 60.21138, 60.21138, 60.21138, 60.21139, 60.21141,
+ 60.21143, 60.21146, 60.21149, 60.21152, 60.21154, 60.21157, 60.21159, 60.21162, 60.21164,
+ 60.21167, 60.21169, 60.21172, 60.21174, 60.21177, 60.21179, 60.21181, 60.21184, 60.21186,
+ 60.21189, 60.21191, 60.21194, 60.21196, 60.21199, 60.21201, 60.21204, 60.21206, 60.21208,
+ 60.21211, 60.21213, 60.21215, 60.21217, 60.2122, 60.21222, 60.21224, 60.21227, 60.21229,
+ 60.21231, 60.21234, 60.21236, 60.21238, 60.2124, 60.21243, 60.21245, 60.21247, 60.21249,
+ 60.21252, 60.21254, 60.21257, 60.21259, 60.21261, 60.21263, 60.21266, 60.21268, 60.21271,
+ 60.21273, 60.21276, 60.21278, 60.2128, 60.21283, 60.21285, 60.21288, 60.2129, 60.21293,
+ 60.21295, 60.21297, 60.213, 60.21302, 60.21304, 60.21307, 60.2131, 60.21312, 60.21315,
+ 60.21317, 60.2132, 60.21322, 60.21325, 60.21327, 60.2133, 60.21332, 60.21335, 60.21337,
+ 60.2134, 60.21342, 60.21345, 60.21347, 60.21349, 60.21351, 60.21354, 60.21356, 60.21358,
+ 60.2136, 60.21363, 60.21365, 60.21367, 60.21369, 60.21372, 60.21374, 60.21377, 60.21379,
+ 60.21382, 60.21384, 60.21386, 60.21389, 60.21391, 60.21394, 60.21396, 60.21399, 60.21401,
+ 60.21404, 60.21406, 60.21409, 60.21412, 60.21414, 60.21416, 60.21419, 60.21421, 60.21424,
+ 60.21426, 60.21429, 60.21431, 60.21433, 60.21436, 60.21438, 60.21441, 60.21443, 60.21445,
+ 60.21448, 60.2145, 60.21453, 60.21456, 60.21458, 60.2146, 60.21463, 60.21465, 60.21467,
+ 60.2147, 60.21472, 60.21474, 60.21477, 60.21479, 60.21481, 60.21484, 60.21486, 60.21489,
+ 60.21491, 60.21494, 60.21496, 60.21499, 60.21501, 60.21504, 60.21506, 60.21509, 60.21511,
+ 60.21513, 60.21516, 60.21518, 60.21521, 60.21523, 60.21526, 60.21528, 60.21531, 60.21533,
+ 60.21536, 60.21538, 60.21541, 60.21543, 60.21546, 60.21548, 60.21551, 60.21554, 60.21556,
+ 60.21558, 60.21561, 60.21564, 60.21566, 60.21569, 60.21571, 60.21573, 60.21576, 60.21578,
+ 60.21581, 60.21583, 60.21585, 60.21588, 60.2159, 60.21592, 60.21595, 60.21597, 60.216,
+ 60.21602, 60.21604, 60.21606, 60.21609, 60.21611, 60.21613, 60.21616, 60.21618, 60.2162,
+ 60.21623, 60.21625, 60.21627, 60.2163, 60.21632, 60.21634, 60.21637, 60.21639, 60.21642,
+ 60.21644, 60.21646, 60.21649, 60.21651, 60.21653, 60.21654, 60.21654, 60.21655, 60.21656,
+ 60.21658, 60.2166, 60.21662, 60.21664, 60.21666, 60.21668, 60.21671, 60.21673, 60.21675,
+ 60.21677, 60.21679, 60.21681, 60.21683, 60.21684, 60.21686, 60.21687, 60.21689, 60.21691,
+ 60.21692, 60.21693, 60.21695, 60.21696, 60.21698, 60.217, 60.21702, 60.21704, 60.21706,
+ 60.21708, 60.2171, 60.21711, 60.21713, 60.21716, 60.21719, 60.21721, 60.21722, 60.21724,
+ 60.21727, 60.21729, 60.21731, 60.21733, 60.21735, 60.21737, 60.21739, 60.2174, 60.21742,
+ 60.21744, 60.21745, 60.21747, 60.21748, 60.21749, 60.2175, 60.21752, 60.21752, 60.21754,
+ 60.21755, 60.21757, 60.21762, 60.2177, 60.21778, 60.21786, 60.21794, 60.21796, 60.21801,
+ 60.21806, 60.21809, 60.21812, 60.21813, 60.21814, 60.21815, 60.21815, 60.21816, 60.21816,
+ 60.21816, 60.21816, 60.21816, 60.21817, 60.21818, 60.21819, 60.2182, 60.2182, 60.21827,
+ 60.21836, 60.21844, 60.21852, 60.21858, 60.21865, 60.2187, 60.21873, 60.21875, 60.21877,
+ 60.21877, 60.21878, 60.21879, 60.2188, 60.21882, 60.21883, 60.21883, 60.21884, 60.21884,
+ 60.21884, 60.21884, 60.21885, 60.21884, 60.21884, 60.21884, 60.21883, 60.21882, 60.21881,
+ 60.2188, 60.21879, 60.21878, 60.21878, 60.21878, 60.21878, 60.21878, 60.21878, 60.21879,
+ 60.21879, 60.2188, 60.21881, 60.21882, 60.21883, 60.21883, 60.21884, 60.21884, 60.21885,
+ 60.21885, 60.21886, 60.21887, 60.21888, 60.21888, 60.21889, 60.21889, 60.21889, 60.21888,
+ 60.21889, 60.21889, 60.2189, 60.21891, 60.21892, 60.21894, 60.21896, 60.21898, 60.219,
+ 60.21902, 60.21904, 60.21906, 60.21908, 60.2191, 60.21912, 60.21914, 60.21916, 60.21918,
+ 60.2192, 60.21922, 60.21924, 60.21926, 60.21928, 60.2193, 60.21932, 60.21934, 60.21936,
+ 60.21938, 60.2194, 60.21942, 60.21944, 60.21951, 60.21953, 60.21956, 60.21957, 60.21958,
+ 60.2196, 60.21963, 60.21971, 60.21976, 60.21977, 60.21979, 60.2198, 60.21983, 60.21984,
+ 60.21986, 60.21988, 60.2199, 60.21992, 60.21994, 60.21996, 60.21998, 60.21999, 60.22008,
+ 60.22015, 60.22017, 60.2202, 60.22021, 60.22022, 60.22029, 60.22033, 60.22037, 60.22039,
+ 60.22041, 60.22043, 60.22045, 60.22047, 60.22049, 60.22051, 60.22053, 60.22056, 60.22058,
+ 60.2206, 60.22062, 60.22064, 60.22066, 60.22067, 60.22069, 60.22071, 60.22073, 60.22075,
+ 60.22078, 60.22079, 60.22081, 60.22083, 60.22085, 60.22087, 60.22089, 60.22092, 60.22094,
+ 60.22096, 60.22098, 60.221, 60.22103, 60.22105, 60.22106, 60.22107, 60.22109, 60.2211,
+ 60.22112, 60.22113, 60.22114, 60.22115, 60.22117, 60.22118, 60.22119, 60.2212, 60.22122,
+ 60.22124, 60.22124, 60.22124, 60.22123, 60.22122, 60.22121, 60.2212, 60.2212, 60.2212,
+ 60.2212, 60.2212, 60.22121, 60.22125, 60.22127, 60.22129, 60.2213, 60.22132, 60.22134,
+ 60.22136, 60.22138, 60.2214, 60.22142, 60.22144, 60.22146, 60.22148, 60.2215, 60.22153,
+ 60.22155, 60.22158, 60.2216, 60.22162, 60.22164, 60.22166, 60.22168, 60.2217, 60.22172,
+ 60.22174, 60.22176, 60.22179, 60.22182, 60.22184, 60.22188, 60.22192, 60.22194, 60.22197,
+ 60.222, 60.22202, 60.22205, 60.22207, 60.2221, 60.22211, 60.22213, 60.22215, 60.22217,
+ 60.22219, 60.22222, 60.22224, 60.22227, 60.22229, 60.22232, 60.22234, 60.22236, 60.22237,
+ 60.22238, 60.22239, 60.22241, 60.22243, 60.22245, 60.22248, 60.2225, 60.22252, 60.22254,
+ 60.22255, 60.22258, 60.22259, 60.22264, 60.22271, 60.22274, 60.22276, 60.22278, 60.22281,
+ 60.22283, 60.22287, 60.22289, 60.22292, 60.22294, 60.22297, 60.223, 60.22303, 60.22306,
+ 60.22309, 60.22312, 60.22316, 60.22318, 60.22321, 60.22324, 60.22328, 60.2233, 60.22332,
+ 60.22335, 60.22337, 60.22338, 60.2234, 60.22342, 60.22345, 60.22347, 60.22349, 60.22351,
+ 60.22352, 60.22354, 60.22355, 60.22357, 60.22358, 60.2236, 60.22362, 60.22363, 60.22365,
+ 60.22368, 60.2237, 60.22371, 60.22373, 60.22375, 60.22377, 60.22378, 60.2238, 60.22381,
+ 60.22384, 60.22385, 60.22387, 60.22389, 60.22398, 60.22404, 60.22409, 60.2241, 60.22412,
+ 60.22414, 60.22416, 60.22417, 60.22418, 60.22419, 60.22421, 60.22422, 60.22424, 60.22425,
+ 60.22427, 60.22429, 60.22431, 60.22434, 60.22436, 60.22439, 60.22441, 60.22443, 60.22445,
+ 60.22447, 60.22449, 60.22457, 60.22465, 60.22471, 60.22472, 60.22474, 60.22475, 60.22477,
+ 60.22478, 60.2248, 60.22486, 60.22489, 60.22491, 60.22493, 60.22495, 60.22497, 60.225,
+ 60.22502, 60.22504, 60.22506, 60.22513, 60.22516, 60.22517, 60.22519, 60.22522, 60.22525,
+ 60.22527, 60.22529, 60.22531, 60.22533, 60.22535, 60.22537, 60.22539, 60.22542, 60.22544,
+ 60.22546, 60.22549, 60.22551, 60.22552, 60.22554, 60.22557, 60.22559, 60.22561, 60.22563,
+ 60.22565, 60.22567, 60.22569, 60.22571, 60.22572, 60.22574, 60.22575, 60.22577, 60.22579,
+ 60.2258, 60.22582, 60.22584, 60.22586, 60.22588, 60.2259, 60.22591, 60.22593, 60.22595,
+ 60.22596, 60.22598, 60.226, 60.22602, 60.22605, 60.22607, 60.22609, 60.22611, 60.22612,
+ 60.22614, 60.22615, 60.22617, 60.22619, 60.2262, 60.22623, 60.22625, 60.22629, 60.22632,
+ 60.22634, 60.22636, 60.22641, 60.22643, 60.22646, 60.22648, 60.22654, 60.22655, 60.22657,
+ 60.22658, 60.2266, 60.22662, 60.22664, 60.22666, 60.22668, 60.22671, 60.22673, 60.22676,
+ 60.22678, 60.22681, 60.22684, 60.22687, 60.22689, 60.22691, 60.22693, 60.22695, 60.22698,
+ 60.227, 60.22703, 60.22705, 60.22707, 60.22709, 60.22711, 60.22713, 60.22715, 60.22717,
+ 60.22719, 60.22727, 60.22729, 60.22732, 60.22734, 60.22735, 60.22738, 60.22741, 60.22743,
+ 60.22744, 60.22747, 60.22751, 60.22753, 60.22755, 60.22757, 60.22759, 60.22761, 60.22763,
+ 60.22765, 60.22767, 60.22769, 60.22771, 60.22773, 60.22775, 60.22779, 60.22782, 60.22784,
+ 60.22786, 60.22789, 60.22791, 60.22793, 60.22796, 60.22798, 60.228, 60.22803, 60.22806,
+ 60.22808, 60.2281, 60.22813, 60.22815, 60.22817, 60.22821, 60.22824, 60.22826, 60.22829,
+ 60.22832, 60.22835, 60.22838, 60.2284, 60.22842, 60.22844, 60.22846, 60.22848, 60.22849,
+ 60.2285, 60.2285, 60.2285, 60.2285, 60.22849, 60.22849, 60.22849, 60.22848, 60.22847,
+ 60.22846, 60.22845, 60.22844, 60.22843, 60.22842, 60.22841, 60.2284, 60.22839, 60.22838,
+ 60.22837, 60.22836, 60.22835, 60.22834, 60.22833, 60.22832, 60.22831, 60.2283, 60.22829,
+ 60.22828, 60.22827, 60.22826, 60.22826, 60.22825, 60.22825, 60.22824, 60.22824, 60.22823,
+ 60.22823, 60.22823, 60.22823, 60.22823, 60.22824, 60.22824, 60.22824, 60.22825, 60.22826,
+ 60.22826, 60.22827, 60.22827, 60.22827, 60.22827, 60.22827, 60.22827, 60.22827, 60.22827,
+ 60.22827, 60.22827, 60.22826, 60.22826, 60.22826, 60.22826, 60.22827, 60.22827, 60.22827,
+ 60.22827, 60.22828, 60.22828, 60.22829, 60.22829, 60.22829, 60.22829, 60.22829, 60.22829,
+ 60.22829, 60.22829, 60.22829, 60.22829, 60.22829, 60.22829, 60.22829, 60.22829, 60.22829,
+ 60.22829, 60.22828, 60.22828, 60.22827, 60.22827, 60.22826, 60.22826, 60.22824, 60.22823,
+ 60.22822, 60.2282, 60.22818, 60.22817, 60.22816, 60.22814, 60.22813, 60.22811, 60.2281,
+ 60.22808, 60.22807, 60.22805, 60.22804, 60.22803, 60.22802, 60.22801, 60.22799, 60.22798,
+ 60.22797, 60.22796, 60.22794, 60.22793, 60.22792, 60.2279, 60.22789, 60.22787, 60.22786,
+ 60.22785, 60.22784, 60.22782, 60.22781, 60.2278, 60.22779, 60.22777, 60.22776, 60.22774,
+ 60.22773, 60.22771, 60.22769, 60.22767, 60.22765, 60.22763, 60.22761, 60.22759, 60.22757,
+ 60.22755, 60.22753, 60.22751, 60.22749, 60.22748, 60.22747, 60.22747, 60.22748, 60.22749,
+ 60.2275, 60.22752, 60.22754, 60.22756, 60.22757, 60.22759, 60.2276, 60.22762, 60.22763,
+ 60.22764, 60.22766, 60.22767, 60.22767, 60.22768, 60.22768, 60.22768, 60.22768, 60.22769,
+ 60.2277, 60.2277, 60.22771, 60.22772, 60.22772, 60.22774, 60.22775, 60.22776, 60.22777,
+ 60.22778, 60.2278, 60.22781, 60.22782, 60.22784, 60.22784, 60.22785, 60.22786, 60.22787,
+ 60.22788, 60.2279, 60.22792, 60.22793, 60.22795, 60.22797, 60.22799, 60.228, 60.22802,
+ 60.22803, 60.22804, 60.22804, 60.22803, 60.22801, 60.22798, 60.22796, 60.22793, 60.22791,
+ 60.22789, 60.22788, 60.22787, 60.22786, 60.22786, 60.22785, 60.22785, 60.22784, 60.22784,
+ 60.22784, 60.22783, 60.22783, 60.22782, 60.22781, 60.22781, 60.22781, 60.22782, 60.22782,
+ 60.22782, 60.22782, 60.22782, 60.22782, 60.22781, 60.22781, 60.22781, 60.22781, 60.22782,
+ 60.22782, 60.22782, 60.22782, 60.22782, 60.22782, 60.22782, 60.22782, 60.22782, 60.22782,
+ 60.22781, 60.22781, 60.22781, 60.22781, 60.2278, 60.2278, 60.2278, 60.2278, 60.2278,
+ 60.22779, 60.22779, 60.22779, 60.22778, 60.22777, 60.22776, 60.22776, 60.22775, 60.22775,
+ 60.22775, 60.22775, 60.22775, 60.22775, 60.22775, 60.22776, 60.22775, 60.22775, 60.22774,
+ 60.22774, 60.22773, 60.22773, 60.22772, 60.22772, 60.22772, 60.22771, 60.22771, 60.22771,
+ 60.2277, 60.22769, 60.22767, 60.22765, 60.22763, 60.2276, 60.22759, 60.22757, 60.22756,
+ 60.22754, 60.22752, 60.2275, 60.22748, 60.22746, 60.22745, 60.22743, 60.22742, 60.2274,
+ 60.22738, 60.22737, 60.22734, 60.22732, 60.2273, 60.22728, 60.22726, 60.22725, 60.22723,
+ 60.22721, 60.2272, 60.22718, 60.22717, 60.22715, 60.22713, 60.22711, 60.22709, 60.22706,
+ 60.22704, 60.22702, 60.22699, 60.22696, 60.22693, 60.22691, 60.22688, 60.22686, 60.22683,
+ 60.22679, 60.22676, 60.22673, 60.2267, 60.22666, 60.22662, 60.22659, 60.22655, 60.22652,
+ 60.22649, 60.22645, 60.22642, 60.22638, 60.22635, 60.22632, 60.22629, 60.22626, 60.22622,
+ 60.22619, 60.22615, 60.22612, 60.22608, 60.22605, 60.22601, 60.22598, 60.22595, 60.22592,
+ 60.22588, 60.22585, 60.22582, 60.22579, 60.22575, 60.22571, 60.22567, 60.22564, 60.2256,
+ 60.22556, 60.22552, 60.22548, 60.22545, 60.22541, 60.22537, 60.22534, 60.2253, 60.22526,
+ 60.22522, 60.22518, 60.22514, 60.2251, 60.22506, 60.22503, 60.22499, 60.22496, 60.22491,
+ 60.22487)
+
+internal val longs = listOf(25.07488, 25.07488, 25.07487, 25.07485, 25.07483, 25.07481, 25.07478,
+ 25.07476, 25.07474, 25.07471, 25.07468, 25.07464, 25.0746, 25.07457, 25.07455, 25.07454,
+ 25.07452, 25.07451, 25.07448, 25.07447, 25.07445, 25.07443, 25.07436, 25.07429, 25.07419,
+ 25.07418, 25.07414, 25.07401, 25.07392, 25.07391, 25.07383, 25.07381, 25.0738, 25.07379,
+ 25.07378, 25.07375, 25.0737, 25.07367, 25.07365, 25.07362, 25.0736, 25.07359, 25.07357,
+ 25.07355, 25.0735, 25.07346, 25.07335, 25.07322, 25.07315, 25.07312, 25.07301, 25.07298,
+ 25.07296, 25.07289, 25.07285, 25.07269, 25.07253, 25.07243, 25.07237, 25.07232, 25.07228,
+ 25.07222, 25.07217, 25.07211, 25.07205, 25.07199, 25.07194, 25.07188, 25.07184, 25.07179,
+ 25.07175, 25.0717, 25.07164, 25.07159, 25.07155, 25.07151, 25.07142, 25.07138, 25.07132,
+ 25.07122, 25.07117, 25.07113, 25.0711, 25.07106, 25.07087, 25.07072, 25.07067, 25.07062,
+ 25.07058, 25.07053, 25.07049, 25.07046, 25.07042, 25.07037, 25.07032, 25.07014, 25.06999,
+ 25.06994, 25.06974, 25.06954, 25.06935, 25.06915, 25.06897, 25.06889, 25.06881, 25.06861,
+ 25.06851, 25.06847, 25.06842, 25.06837, 25.06833, 25.06814, 25.06791, 25.06786, 25.06765,
+ 25.06759, 25.06754, 25.06748, 25.06743, 25.06738, 25.06733, 25.06728, 25.06706, 25.06684,
+ 25.06673, 25.06669, 25.06664, 25.0666, 25.06655, 25.06637, 25.06618, 25.06595, 25.06575,
+ 25.06561, 25.06557, 25.06552, 25.06545, 25.06541, 25.06535, 25.06529, 25.06523, 25.06515,
+ 25.06509, 25.06505, 25.06502, 25.06498, 25.06494, 25.06486, 25.06481, 25.06469, 25.06466,
+ 25.06462, 25.06457, 25.06453, 25.06447, 25.06429, 25.06409, 25.06386, 25.06371, 25.06367,
+ 25.06362, 25.06357, 25.06352, 25.06348, 25.06344, 25.06337, 25.06333, 25.06328, 25.06323,
+ 25.06318, 25.06314, 25.06309, 25.06304, 25.06298, 25.06293, 25.06288, 25.06283, 25.0628,
+ 25.06275, 25.0627, 25.06264, 25.06259, 25.06254, 25.06248, 25.06243, 25.06239, 25.06234,
+ 25.06229, 25.06224, 25.06219, 25.06215, 25.06209, 25.06205, 25.062, 25.06195, 25.0619,
+ 25.06186, 25.06183, 25.0618, 25.06177, 25.06173, 25.06169, 25.06165, 25.0616, 25.06157,
+ 25.06152, 25.06148, 25.06143, 25.06138, 25.06134, 25.0613, 25.06126, 25.06122, 25.06118,
+ 25.06113, 25.06109, 25.06104, 25.06099, 25.06095, 25.0609, 25.06086, 25.06082, 25.06078,
+ 25.06074, 25.06069, 25.06064, 25.0606, 25.06056, 25.06052, 25.06047, 25.06042, 25.06036,
+ 25.06031, 25.06026, 25.06021, 25.06015, 25.06011, 25.06006, 25.06001, 25.05995, 25.0599,
+ 25.05985, 25.0598, 25.05975, 25.0597, 25.05965, 25.0596, 25.05955, 25.0595, 25.05946,
+ 25.05941, 25.05937, 25.05932, 25.05928, 25.05923, 25.05919, 25.05914, 25.0591, 25.05905,
+ 25.059, 25.05895, 25.0589, 25.05886, 25.05881, 25.05876, 25.05871, 25.05866, 25.05861,
+ 25.05856, 25.0585, 25.05846, 25.05841, 25.05837, 25.05832, 25.05827, 25.05823, 25.05819,
+ 25.05815, 25.0581, 25.05805, 25.05801, 25.05797, 25.05792, 25.05787, 25.05782, 25.05776,
+ 25.05771, 25.05766, 25.0576, 25.05754, 25.05748, 25.05742, 25.05736, 25.0573, 25.05724,
+ 25.05707, 25.05703, 25.05698, 25.05693, 25.05689, 25.05684, 25.0568, 25.05676, 25.05672,
+ 25.05668, 25.05663, 25.05659, 25.05654, 25.05649, 25.05644, 25.05638, 25.05633, 25.05619,
+ 25.05616, 25.05613, 25.0561, 25.05608, 25.05607, 25.05606, 25.05605, 25.05603, 25.05602,
+ 25.056, 25.05598, 25.05594, 25.05591, 25.05593, 25.05593, 25.05594, 25.05595, 25.05595,
+ 25.05596, 25.05597, 25.05598, 25.05599, 25.05599, 25.05598, 25.05599, 25.05598, 25.05597,
+ 25.05597, 25.05595, 25.05595, 25.05593, 25.05592, 25.0559, 25.05589, 25.05588, 25.05576,
+ 25.05565, 25.05554, 25.05547, 25.05541, 25.05532, 25.05521, 25.0551, 25.05507, 25.05499,
+ 25.05494, 25.05488, 25.0548, 25.05473, 25.0547, 25.05467, 25.05454, 25.05441, 25.0543,
+ 25.05418, 25.05407, 25.05404, 25.05397, 25.05392, 25.05388, 25.05383, 25.0538, 25.05375,
+ 25.05372, 25.0537, 25.05367, 25.05364, 25.0536, 25.05354, 25.05348, 25.05329, 25.05309,
+ 25.05298, 25.05292, 25.05289, 25.05286, 25.05283, 25.05279, 25.05275, 25.05272, 25.05268,
+ 25.05265, 25.05261, 25.05258, 25.05255, 25.0525, 25.05244, 25.05241, 25.05237, 25.05233,
+ 25.0523, 25.05226, 25.05223, 25.0522, 25.05215, 25.05211, 25.05206, 25.05203, 25.052,
+ 25.05197, 25.05193, 25.05189, 25.05188, 25.05187, 25.05186, 25.05186, 25.05184, 25.05183,
+ 25.05181, 25.05178, 25.05176, 25.05173, 25.0517, 25.05166, 25.05164, 25.05161, 25.05156,
+ 25.05153, 25.0515, 25.05148, 25.05146, 25.05143, 25.05141, 25.05136, 25.05133, 25.05131,
+ 25.05128, 25.05127, 25.05129, 25.05129, 25.05129, 25.05128, 25.05128, 25.05129, 25.0513,
+ 25.05132, 25.05134, 25.05137, 25.05137, 25.05137, 25.05137, 25.05137, 25.05137, 25.05136,
+ 25.05136, 25.05135, 25.05133, 25.05131, 25.05129, 25.05128, 25.05126, 25.05124, 25.05121,
+ 25.05119, 25.05117, 25.05115, 25.05113, 25.05111, 25.05108, 25.05106, 25.05104, 25.05101,
+ 25.05099, 25.05095, 25.05091, 25.05087, 25.05083, 25.05079, 25.05076, 25.05074, 25.05072,
+ 25.05072, 25.05071, 25.05069, 25.05069, 25.05067, 25.05065, 25.05063, 25.0506, 25.05058,
+ 25.05055, 25.05053, 25.05051, 25.05049, 25.05048, 25.05046, 25.05045, 25.05044, 25.05041,
+ 25.0504, 25.05039, 25.05038, 25.05037, 25.05037, 25.05037, 25.05038, 25.05039, 25.05048,
+ 25.05049, 25.05049, 25.05049, 25.05048, 25.05045, 25.05045, 25.05045, 25.05045, 25.05046,
+ 25.05047, 25.05049, 25.05051, 25.05055, 25.0506, 25.05066, 25.05071, 25.05076, 25.05079,
+ 25.05082, 25.05084, 25.05087, 25.0509, 25.05092, 25.05093, 25.05094, 25.05092, 25.05091,
+ 25.0509, 25.05081, 25.05064, 25.05059, 25.05054, 25.05049, 25.05044, 25.05039, 25.05034,
+ 25.05029, 25.05025, 25.0502, 25.05014, 25.04998, 25.04993, 25.04979, 25.0496, 25.04943,
+ 25.04928, 25.04911, 25.04891, 25.04871, 25.04851, 25.0483, 25.04809, 25.0479, 25.04771,
+ 25.04751, 25.04732, 25.04712, 25.04693, 25.04676, 25.04658, 25.04638, 25.04631, 25.04614,
+ 25.04599, 25.04582, 25.04566, 25.04548, 25.04526, 25.04504, 25.04486, 25.04469, 25.0445,
+ 25.04434, 25.04416, 25.04402, 25.04384, 25.04373, 25.04361, 25.04354, 25.04348, 25.04342,
+ 25.04336, 25.04331, 25.04327, 25.04322, 25.04316, 25.04298, 25.04281, 25.04265, 25.04243,
+ 25.04223, 25.04206, 25.04189, 25.04168, 25.04149, 25.04127, 25.04111, 25.04106, 25.04101,
+ 25.04095, 25.0409, 25.04084, 25.04079, 25.04068, 25.04062, 25.04057, 25.04051, 25.04046,
+ 25.04041, 25.04035, 25.0403, 25.04025, 25.04019, 25.04013, 25.04007, 25.04001, 25.03995,
+ 25.03989, 25.03983, 25.03978, 25.03974, 25.0397, 25.03966, 25.0396, 25.03955, 25.03949,
+ 25.03943, 25.03937, 25.03932, 25.03926, 25.03909, 25.03906, 25.03902, 25.039, 25.03897,
+ 25.03894, 25.03892, 25.0389, 25.03887, 25.03885, 25.03882, 25.0388, 25.03877, 25.03875,
+ 25.03872, 25.03869, 25.03867, 25.03864, 25.03861, 25.03859, 25.03856, 25.03855, 25.03852,
+ 25.03849, 25.03847, 25.03844, 25.03841, 25.03839, 25.03836, 25.03834, 25.03832, 25.03829,
+ 25.03827, 25.03825, 25.03823, 25.0382, 25.03817, 25.03814, 25.03811, 25.03809, 25.03806,
+ 25.03804, 25.03801, 25.03799, 25.03797, 25.03794, 25.03792, 25.0379, 25.03788, 25.03785,
+ 25.03783, 25.0378, 25.03778, 25.03775, 25.03772, 25.0377, 25.03768, 25.03765, 25.03763,
+ 25.03761, 25.03758, 25.03756, 25.03753, 25.0375, 25.03748, 25.03746, 25.03744, 25.03742,
+ 25.03739, 25.03736, 25.03733, 25.0373, 25.03727, 25.03724, 25.03722, 25.03719, 25.03717,
+ 25.03714, 25.03712, 25.0371, 25.03708, 25.03705, 25.03702, 25.037, 25.03698, 25.03695,
+ 25.03693, 25.0369, 25.03687, 25.03684, 25.03681, 25.03679, 25.03675, 25.03671, 25.03667,
+ 25.03663, 25.03659, 25.03651, 25.03635, 25.03627, 25.03623, 25.03618, 25.03611, 25.03606,
+ 25.03602, 25.03595, 25.03591, 25.03586, 25.03581, 25.03576, 25.03573, 25.03569, 25.03565,
+ 25.03561, 25.03557, 25.03553, 25.03548, 25.03544, 25.03538, 25.03533, 25.03528, 25.03524,
+ 25.03519, 25.03513, 25.03508, 25.03502, 25.03497, 25.03493, 25.03488, 25.03483, 25.03479,
+ 25.03474, 25.03469, 25.03464, 25.03459, 25.03454, 25.03448, 25.03443, 25.03438, 25.03433,
+ 25.03428, 25.03424, 25.03419, 25.03414, 25.0341, 25.03405, 25.034, 25.03396, 25.03392,
+ 25.03387, 25.03384, 25.0338, 25.03374, 25.03369, 25.03365, 25.0336, 25.03356, 25.03352,
+ 25.03348, 25.03344, 25.0334, 25.03337, 25.03332, 25.03328, 25.03324, 25.03318, 25.03312,
+ 25.03306, 25.03301, 25.03295, 25.03289, 25.03284, 25.03279, 25.03274, 25.03269, 25.03263,
+ 25.03257, 25.03251, 25.03246, 25.0324, 25.03234, 25.03229, 25.03224, 25.03218, 25.03213,
+ 25.03208, 25.03202, 25.03197, 25.03191, 25.03185, 25.03179, 25.03174, 25.03168, 25.03163,
+ 25.03157, 25.03152, 25.03147, 25.03142, 25.03137, 25.03132, 25.03127, 25.03122, 25.03117,
+ 25.03112, 25.03107, 25.03102, 25.0308, 25.03059, 25.03049, 25.03044, 25.03039, 25.03035,
+ 25.03031, 25.03027, 25.03023, 25.03018, 25.03013, 25.03003, 25.02996, 25.0299, 25.02985,
+ 25.02978, 25.02973, 25.02968, 25.02947, 25.02942, 25.02937, 25.02932, 25.02927, 25.02905,
+ 25.02894, 25.02888, 25.02883, 25.0286, 25.02838, 25.02818, 25.02797, 25.02777, 25.02763,
+ 25.02758, 25.02754, 25.02749, 25.02743, 25.02738, 25.02733, 25.02729, 25.02724, 25.02719,
+ 25.02714, 25.02709, 25.02704, 25.02699, 25.02693, 25.02687, 25.02682, 25.02676, 25.0267,
+ 25.02664, 25.02658, 25.02652, 25.02647, 25.02641, 25.02618, 25.02607, 25.02602, 25.02582,
+ 25.02563, 25.02543, 25.02525, 25.02507, 25.02488, 25.02472, 25.02453, 25.02447, 25.02442,
+ 25.02437, 25.02429, 25.02419, 25.02411, 25.02407, 25.02399, 25.02382, 25.02362, 25.02347,
+ 25.02343, 25.02338, 25.02334, 25.02329, 25.02324, 25.02319, 25.02314, 25.02308, 25.02303,
+ 25.02298, 25.02292, 25.02287, 25.02271, 25.02256, 25.02244, 25.02238, 25.02235, 25.02232,
+ 25.0223, 25.02228, 25.02226, 25.02224, 25.02221, 25.02219, 25.02216, 25.02213, 25.02211,
+ 25.02209, 25.02207, 25.02204, 25.02202, 25.02201, 25.02199, 25.02197, 25.02194, 25.02192,
+ 25.0219, 25.02187, 25.02186, 25.02184, 25.02182, 25.0218, 25.02178, 25.02176, 25.02174,
+ 25.02172, 25.0217, 25.02168, 25.02166, 25.02164, 25.02161, 25.02158, 25.02156, 25.02154,
+ 25.02151, 25.02149, 25.02148, 25.02147, 25.02147, 25.02148, 25.02148, 25.02148, 25.02146,
+ 25.02144, 25.0214, 25.02138, 25.02133, 25.02129, 25.02107, 25.02086, 25.0207, 25.02065,
+ 25.0206, 25.02056, 25.02051, 25.02044, 25.02037, 25.02031, 25.02011, 25.02004, 25.01999,
+ 25.01993, 25.01986, 25.01982, 25.01977, 25.01972, 25.01966, 25.01961, 25.01957, 25.01951,
+ 25.01947, 25.01942, 25.01938, 25.01935, 25.01931, 25.01927, 25.01922, 25.01917, 25.01914,
+ 25.01901, 25.01887, 25.0187, 25.01851, 25.01829, 25.01809, 25.01804, 25.01799, 25.01794,
+ 25.01789, 25.01784, 25.01779, 25.01759, 25.01743, 25.01724, 25.01714, 25.01716, 25.01719,
+ 25.01721, 25.01723, 25.01724, 25.01724, 25.01723, 25.01722, 25.01722, 25.01721, 25.0172,
+ 25.01719, 25.01718, 25.01717, 25.01714, 25.01713, 25.01711, 25.01707, 25.01704, 25.01701,
+ 25.01697, 25.01694, 25.01691, 25.01687, 25.01684, 25.01681, 25.01677, 25.01674, 25.01671,
+ 25.01668, 25.01665, 25.01661, 25.0166, 25.01648, 25.01634, 25.01618, 25.01601, 25.01584,
+ 25.01568, 25.01553, 25.01539, 25.01525, 25.01519, 25.01516, 25.01513, 25.0151, 25.01507,
+ 25.01504, 25.01501, 25.01489, 25.01475, 25.01464, 25.01451, 25.01437, 25.01427, 25.01421,
+ 25.01416, 25.01414, 25.01415, 25.01416, 25.01418, 25.01419, 25.0142, 25.01421, 25.01422,
+ 25.01424, 25.01426, 25.01429, 25.01431, 25.01433, 25.01435, 25.01436, 25.01439, 25.01441,
+ 25.01445, 25.01448, 25.01452, 25.01456, 25.0146, 25.01463, 25.01466, 25.01469, 25.01472,
+ 25.01475, 25.01476, 25.01479, 25.01482, 25.01484, 25.01487, 25.0149, 25.01492, 25.01491,
+ 25.01491, 25.01488, 25.01483, 25.01478, 25.01471, 25.01465, 25.01447, 25.01428, 25.01411,
+ 25.01395, 25.01377, 25.01358, 25.01338, 25.01317, 25.01299, 25.01281, 25.01264, 25.01244,
+ 25.01227, 25.01204, 25.01185, 25.01179, 25.01174, 25.01168, 25.01163, 25.01158, 25.01153,
+ 25.01148, 25.01143, 25.01138, 25.01133, 25.01128, 25.01123, 25.01118, 25.01112, 25.01108,
+ 25.01103, 25.01098, 25.01093, 25.01089, 25.01084, 25.0108, 25.01074, 25.0107, 25.01065,
+ 25.0106, 25.01055, 25.01051, 25.01046, 25.01041, 25.01037, 25.01032, 25.01027, 25.01022,
+ 25.01017, 25.01012, 25.01007, 25.01002, 25.00997, 25.00992, 25.00988, 25.00983, 25.00979,
+ 25.00974, 25.0097, 25.00965, 25.0096, 25.00956, 25.00951, 25.00947, 25.00941, 25.00936,
+ 25.00918, 25.009, 25.00882, 25.00871, 25.00865, 25.00862, 25.00861, 25.00859, 25.00857,
+ 25.00856, 25.00854, 25.00854, 25.00852, 25.00851, 25.0085, 25.00849, 25.00848, 25.00847,
+ 25.00845, 25.00844, 25.00842, 25.00841, 25.00839, 25.00837, 25.00836, 25.00835, 25.00833,
+ 25.00831, 25.0083, 25.00828, 25.00827, 25.00825, 25.00824, 25.00823, 25.00822, 25.00821,
+ 25.0082, 25.00818, 25.00816, 25.00815, 25.00814, 25.00814, 25.00814, 25.00813, 25.00814,
+ 25.00814, 25.00814, 25.00814, 25.00814, 25.00814, 25.00814, 25.00814, 25.00814, 25.00814,
+ 25.00814, 25.00815, 25.00815, 25.00815, 25.00815, 25.00814, 25.00814, 25.00813, 25.00813,
+ 25.00813, 25.00812, 25.00812, 25.00813, 25.00812, 25.00813, 25.00813, 25.00813, 25.00815,
+ 25.00816, 25.00816, 25.00817, 25.00818, 25.0082, 25.00822, 25.00826, 25.00829, 25.00832,
+ 25.00835, 25.00838, 25.00852, 25.00854, 25.00856, 25.00862, 25.00865, 25.00867, 25.0087,
+ 25.00873, 25.00875, 25.00876, 25.00877, 25.00879, 25.00881, 25.00883, 25.00885, 25.00885,
+ 25.00887, 25.00889, 25.00889, 25.00891, 25.00893, 25.00895, 25.00897, 25.00899, 25.00902,
+ 25.00905, 25.00907, 25.0091, 25.00914, 25.00917, 25.00918, 25.0092, 25.00922, 25.00923,
+ 25.00925, 25.00925, 25.00926, 25.00928, 25.00929, 25.0093, 25.00931, 25.00932, 25.00932,
+ 25.00932, 25.00933, 25.00933, 25.00933, 25.00934, 25.00935, 25.00936, 25.00937, 25.00938,
+ 25.00939, 25.0094, 25.00941, 25.00942, 25.00943, 25.00947, 25.00949, 25.00955, 25.00963,
+ 25.00965, 25.00967, 25.0097, 25.00971, 25.00973, 25.00976, 25.00978, 25.0098, 25.00982,
+ 25.00983, 25.00984, 25.00985, 25.00984, 25.00984, 25.00984, 25.00983, 25.00981, 25.0098,
+ 25.00978, 25.00977, 25.00977, 25.00976, 25.00976, 25.00977, 25.00978, 25.00978, 25.0098,
+ 25.00982, 25.00984, 25.00985, 25.00986, 25.00987, 25.00988, 25.00989, 25.0099, 25.00992,
+ 25.00994, 25.00996, 25.00998, 25.00999, 25.01001, 25.01004, 25.01008, 25.01012, 25.01016,
+ 25.01021, 25.01024, 25.01028, 25.01032, 25.01036, 25.0104, 25.01044, 25.01047, 25.01051,
+ 25.01056, 25.01059, 25.01063, 25.0107, 25.01075, 25.01079, 25.01084, 25.01088, 25.01093,
+ 25.01097, 25.01102, 25.01106, 25.0111, 25.01115, 25.01119, 25.01123, 25.01131, 25.01135,
+ 25.01139, 25.01144, 25.01147, 25.01152, 25.01156, 25.01161, 25.01166, 25.01171, 25.01177,
+ 25.01201, 25.01217, 25.01234, 25.01253, 25.01274, 25.01294, 25.013, 25.01306, 25.01311,
+ 25.01316, 25.01321, 25.01327, 25.01332, 25.01337, 25.01342, 25.01347, 25.01353, 25.01359,
+ 25.01365, 25.0137, 25.01375, 25.0138, 25.01385, 25.0139, 25.01395, 25.01398, 25.01402,
+ 25.01405, 25.01409, 25.01413, 25.01417, 25.0142, 25.01423, 25.01427, 25.0143, 25.01434,
+ 25.01437, 25.01439, 25.01442, 25.01445, 25.01449, 25.01452, 25.01455, 25.01459, 25.01462,
+ 25.01465, 25.01469, 25.01473, 25.01477, 25.0148, 25.01485, 25.01488, 25.01491, 25.01495,
+ 25.015, 25.01503, 25.01508, 25.01513, 25.01518, 25.01524, 25.01529, 25.01536, 25.01542,
+ 25.01548, 25.01554, 25.0156, 25.01566, 25.01572, 25.01577, 25.01582, 25.01588, 25.01593,
+ 25.01598, 25.01603, 25.01608, 25.01613, 25.01619, 25.01624, 25.01629, 25.01634, 25.01639,
+ 25.01645, 25.01651, 25.01656, 25.01662, 25.01668, 25.01674, 25.0168, 25.01686, 25.01691,
+ 25.01697, 25.01702, 25.01707, 25.01713, 25.01718, 25.01723, 25.01729, 25.01734, 25.01738,
+ 25.01744, 25.01749, 25.01754, 25.01759, 25.01764, 25.01769, 25.01774, 25.01779, 25.01784,
+ 25.01789, 25.01793, 25.01798, 25.01803, 25.01809, 25.01814, 25.01819, 25.01823, 25.01828,
+ 25.01832, 25.01836, 25.01851, 25.01855, 25.01859, 25.01864, 25.01868, 25.01873, 25.01878,
+ 25.01883, 25.01887, 25.01892, 25.01909, 25.01914, 25.01921, 25.01926, 25.01932, 25.01939,
+ 25.01944, 25.0195, 25.01956, 25.01962, 25.01968, 25.01973, 25.01979, 25.01984, 25.0199,
+ 25.01997, 25.02002, 25.02008, 25.02013, 25.02017, 25.02022, 25.02027, 25.02032, 25.02038,
+ 25.02043, 25.02049, 25.02054, 25.0206, 25.02065, 25.0207, 25.02075, 25.0208, 25.02085,
+ 25.0209, 25.02095, 25.021, 25.02106, 25.02111, 25.02116, 25.02121, 25.02127, 25.02132,
+ 25.02137, 25.02142, 25.02147, 25.02152, 25.02157, 25.02162, 25.02168, 25.02173, 25.02178,
+ 25.02183, 25.02188, 25.02193, 25.02199, 25.02203, 25.02208, 25.02213, 25.02217, 25.02221,
+ 25.02225, 25.0223, 25.02235, 25.02239, 25.02244, 25.02248, 25.02252, 25.02257, 25.02261,
+ 25.02265, 25.02269, 25.02272, 25.02276, 25.0228, 25.02284, 25.02288, 25.02291, 25.02294,
+ 25.02298, 25.02302, 25.02305, 25.02309, 25.02313, 25.02316, 25.02319, 25.02322, 25.02326,
+ 25.02329, 25.02332, 25.02336, 25.0234, 25.02344, 25.02349, 25.02352, 25.02357, 25.02361,
+ 25.02366, 25.02371, 25.02375, 25.0238, 25.02384, 25.02387, 25.02391, 25.02394, 25.02399,
+ 25.02404, 25.02409, 25.02415, 25.02419, 25.02423, 25.02427, 25.02432, 25.02436, 25.02441,
+ 25.02445, 25.02449, 25.02454, 25.02457, 25.02462, 25.02466, 25.0247, 25.02474, 25.02477,
+ 25.0248, 25.02483, 25.02485, 25.02491, 25.02493, 25.02498, 25.025, 25.02504, 25.02507,
+ 25.02509, 25.02512, 25.02515, 25.02518, 25.0252, 25.02522, 25.02524, 25.02526, 25.02527,
+ 25.02528, 25.02529, 25.02531, 25.02532, 25.02533, 25.02535, 25.02536, 25.02537, 25.02538,
+ 25.02538, 25.02539, 25.02539, 25.02539, 25.0254, 25.02541, 25.02541, 25.02541, 25.02541,
+ 25.02542, 25.02542, 25.02542, 25.02542, 25.02544, 25.02545, 25.02547, 25.0255, 25.02552,
+ 25.02554, 25.02556, 25.02558, 25.0256, 25.02564, 25.02569, 25.02576, 25.0258, 25.02584,
+ 25.02588, 25.02592, 25.02597, 25.02601, 25.02608, 25.02612, 25.02617, 25.02622, 25.02627,
+ 25.02632, 25.02636, 25.02642, 25.02646, 25.02651, 25.02656, 25.02661, 25.02666, 25.02671,
+ 25.02675, 25.02678, 25.02682, 25.02686, 25.02689, 25.02693, 25.02697, 25.02701, 25.02704,
+ 25.0271, 25.02715, 25.02719, 25.02723, 25.02728, 25.02732, 25.02737, 25.02741, 25.02746,
+ 25.02751, 25.02757, 25.02762, 25.02767, 25.02772, 25.02776, 25.02781, 25.02786, 25.02791,
+ 25.02795, 25.02799, 25.02804, 25.02808, 25.02812, 25.02816, 25.02821, 25.02826, 25.0283,
+ 25.02833, 25.02836, 25.02838, 25.0284, 25.02842, 25.02844, 25.02846, 25.02848, 25.02849,
+ 25.02852, 25.02854, 25.02856, 25.02858, 25.02861, 25.02863, 25.02865, 25.02867, 25.02869,
+ 25.02871, 25.02873, 25.02875, 25.02877, 25.02879, 25.02881, 25.02883, 25.02885, 25.02888,
+ 25.0289, 25.02893, 25.02895, 25.02897, 25.029, 25.02902, 25.02904, 25.02907, 25.02909,
+ 25.02911, 25.02913, 25.02915, 25.02918, 25.0292, 25.02923, 25.02925, 25.02927, 25.0293,
+ 25.02932, 25.02934, 25.02937, 25.02939, 25.02941, 25.02942, 25.02944, 25.02946, 25.02949,
+ 25.02951, 25.02953, 25.02955, 25.02957, 25.02959, 25.02961, 25.02964, 25.02966, 25.02968,
+ 25.02971, 25.02973, 25.02975, 25.02977, 25.02979, 25.02981, 25.02982, 25.02985, 25.02987,
+ 25.02989, 25.02991, 25.02993, 25.02996, 25.02997, 25.02999, 25.03002, 25.03004, 25.03006,
+ 25.03008, 25.03011, 25.03013, 25.03016, 25.03018, 25.03021, 25.03023, 25.03025, 25.03027,
+ 25.03029, 25.03031, 25.03034, 25.03036, 25.03038, 25.0304, 25.03043, 25.03045, 25.03047,
+ 25.03049, 25.03051, 25.03054, 25.03056, 25.03058, 25.03059, 25.03061, 25.03064, 25.03066,
+ 25.03068, 25.0307, 25.03071, 25.03073, 25.03076, 25.03078, 25.0308, 25.03082, 25.03084,
+ 25.03086, 25.03088, 25.03091, 25.03093, 25.03095, 25.03097, 25.03099, 25.03101, 25.03103,
+ 25.03105, 25.03107, 25.03109, 25.03112, 25.03114, 25.03116, 25.03119, 25.03121, 25.03123,
+ 25.03126, 25.03128, 25.0313, 25.03132, 25.03134, 25.03136, 25.03138, 25.0314, 25.03142,
+ 25.03144, 25.03146, 25.03148, 25.0315, 25.03152, 25.03154, 25.03156, 25.03158, 25.03161,
+ 25.03163, 25.03165, 25.03167, 25.03169, 25.03171, 25.03173, 25.03175, 25.03177, 25.0318,
+ 25.03182, 25.03184, 25.03186, 25.03188, 25.0319, 25.03192, 25.03194, 25.03196, 25.03198,
+ 25.032, 25.03202, 25.03205, 25.03207, 25.03209, 25.03211, 25.03213, 25.03216, 25.03218,
+ 25.0322, 25.03223, 25.03225, 25.03227, 25.03229, 25.03231, 25.03233, 25.03234, 25.03236,
+ 25.03238, 25.03241, 25.03243, 25.03245, 25.03248, 25.0325, 25.03253, 25.03255, 25.03257,
+ 25.03259, 25.03261, 25.03263, 25.03265, 25.03268, 25.0327, 25.03272, 25.03274, 25.03276,
+ 25.03278, 25.03279, 25.03282, 25.03284, 25.03288, 25.03292, 25.03296, 25.03301, 25.03304,
+ 25.03308, 25.03311, 25.03313, 25.03315, 25.03317, 25.03318, 25.0332, 25.03322, 25.03325,
+ 25.03329, 25.03332, 25.03337, 25.03341, 25.03346, 25.0335, 25.03355, 25.03359, 25.03364,
+ 25.03367, 25.03371, 25.03376, 25.03381, 25.03385, 25.0339, 25.03396, 25.034, 25.03405,
+ 25.03409, 25.03413, 25.03417, 25.0342, 25.03422, 25.03424, 25.03426, 25.03428, 25.03431,
+ 25.03434, 25.03437, 25.03441, 25.03444, 25.03446, 25.0345, 25.03452, 25.03455, 25.0346,
+ 25.03464, 25.03468, 25.03472, 25.03477, 25.03482, 25.03487, 25.03496, 25.03502, 25.03511,
+ 25.03515, 25.03519, 25.03535, 25.03548, 25.03561, 25.03573, 25.03588, 25.03592, 25.03607,
+ 25.03625, 25.03645, 25.03667, 25.03683, 25.03688, 25.03697, 25.03702, 25.03706, 25.03712,
+ 25.03716, 25.0372, 25.03724, 25.03728, 25.03739, 25.03743, 25.03746, 25.03753, 25.0377,
+ 25.03782, 25.03795, 25.0381, 25.03826, 25.03843, 25.0386, 25.03879, 25.03898, 25.03918,
+ 25.03941, 25.0396, 25.03978, 25.03999, 25.0402, 25.04038, 25.04044, 25.04049, 25.04053,
+ 25.04057, 25.04068, 25.04072, 25.04077, 25.04081, 25.04085, 25.04091, 25.04096, 25.041,
+ 25.04103, 25.04106, 25.04112, 25.04116, 25.0412, 25.04125, 25.04131, 25.04135, 25.0414,
+ 25.04145, 25.0415, 25.04154, 25.04159, 25.04162, 25.04166, 25.04171, 25.04175, 25.04179,
+ 25.04183, 25.04187, 25.04192, 25.04196, 25.04201, 25.04205, 25.04212, 25.04216, 25.0422,
+ 25.04227, 25.0423, 25.04235, 25.0424, 25.04245, 25.04249, 25.04253, 25.04256, 25.0426,
+ 25.04263, 25.04267, 25.0427, 25.04273, 25.04276, 25.0428, 25.04283, 25.04286, 25.04289,
+ 25.04292, 25.04295, 25.04298, 25.04302, 25.04306, 25.04309, 25.04312, 25.04316, 25.04319,
+ 25.04322, 25.04326, 25.04329, 25.04333, 25.04348, 25.0435, 25.04353, 25.04356, 25.04359,
+ 25.04362, 25.04366, 25.04379, 25.04389, 25.04393, 25.04396, 25.04398, 25.04402, 25.04405,
+ 25.04407, 25.04411, 25.04414, 25.04416, 25.0442, 25.04424, 25.04427, 25.0443, 25.04439,
+ 25.04448, 25.04453, 25.0446, 25.04466, 25.04471, 25.04489, 25.04495, 25.04499, 25.045,
+ 25.04502, 25.04504, 25.04506, 25.04507, 25.04508, 25.04509, 25.04511, 25.04512, 25.04513,
+ 25.04515, 25.04515, 25.04516, 25.04518, 25.04521, 25.04526, 25.04528, 25.0453, 25.04533,
+ 25.04535, 25.04537, 25.0454, 25.04542, 25.04544, 25.04547, 25.0455, 25.04554, 25.04558,
+ 25.04561, 25.04565, 25.0457, 25.04575, 25.0458, 25.04585, 25.0459, 25.04595, 25.046,
+ 25.04606, 25.0461, 25.04615, 25.04621, 25.04626, 25.04632, 25.04637, 25.04642, 25.04654,
+ 25.04661, 25.04668, 25.04674, 25.0468, 25.04686, 25.04691, 25.04696, 25.04701, 25.04706,
+ 25.0471, 25.04714, 25.04718, 25.04724, 25.04726, 25.0473, 25.04733, 25.04737, 25.0474,
+ 25.04743, 25.04747, 25.04751, 25.04755, 25.04759, 25.04763, 25.04767, 25.04769, 25.04771,
+ 25.04773, 25.04774, 25.04774, 25.04773, 25.0477, 25.04769, 25.04768, 25.04766, 25.04765,
+ 25.04764, 25.04766, 25.04769, 25.04769, 25.04769, 25.04769, 25.04765, 25.04762, 25.04761,
+ 25.04761, 25.04761, 25.04762, 25.04764, 25.04767, 25.0477, 25.04773, 25.04776, 25.04778,
+ 25.0478, 25.04782, 25.04785, 25.04788, 25.04791, 25.04794, 25.04797, 25.048, 25.04802,
+ 25.04806, 25.04809, 25.04813, 25.04816, 25.0482, 25.04823, 25.04827, 25.0483, 25.04833,
+ 25.04836, 25.04839, 25.04842, 25.04849, 25.04861, 25.04865, 25.0487, 25.04873, 25.04877,
+ 25.04881, 25.04888, 25.04891, 25.04893, 25.04895, 25.04897, 25.04899, 25.04898, 25.04896,
+ 25.04896, 25.04895, 25.04894, 25.04895, 25.04895, 25.04897, 25.04899, 25.049, 25.04901,
+ 25.04902, 25.04905, 25.04907, 25.0491, 25.04912, 25.04915, 25.04917, 25.0492, 25.04923,
+ 25.04927, 25.0493, 25.04934, 25.04939, 25.04944, 25.04948, 25.04953, 25.04958, 25.04962,
+ 25.04966, 25.0497, 25.04974, 25.04978, 25.04982, 25.04985, 25.04988, 25.0499, 25.04993,
+ 25.04994, 25.04997, 25.04999, 25.05002, 25.05013, 25.0503, 25.05039, 25.05041, 25.05044,
+ 25.05046, 25.05048, 25.05051, 25.05055, 25.05059, 25.05063, 25.05068, 25.05074, 25.05079,
+ 25.05085, 25.05091, 25.05096, 25.05101, 25.05105, 25.05109, 25.05113, 25.05117, 25.0512,
+ 25.05124, 25.05128, 25.05142, 25.05153, 25.05167, 25.0517, 25.05174, 25.05176, 25.05179,
+ 25.05182, 25.05185, 25.05196, 25.05203, 25.05206, 25.0521, 25.05211, 25.05214, 25.05218,
+ 25.05222, 25.05224, 25.05228, 25.05243, 25.05255, 25.05261, 25.05262, 25.05265, 25.05267,
+ 25.05269, 25.05272, 25.05275, 25.05279, 25.05283, 25.05286, 25.05289, 25.05293, 25.05297,
+ 25.053, 25.05303, 25.05307, 25.05311, 25.05315, 25.05317, 25.0532, 25.05323, 25.05328,
+ 25.05332, 25.05337, 25.05341, 25.05345, 25.05348, 25.05352, 25.05355, 25.05358, 25.05361,
+ 25.05364, 25.05368, 25.05372, 25.05375, 25.05377, 25.05381, 25.05383, 25.05386, 25.05388,
+ 25.05391, 25.05393, 25.05396, 25.05399, 25.05403, 25.05407, 25.05411, 25.05414, 25.05417,
+ 25.0542, 25.05424, 25.05426, 25.05429, 25.05432, 25.05435, 25.05437, 25.05444, 25.0545,
+ 25.05454, 25.05456, 25.05461, 25.05464, 25.05468, 25.05471, 25.05481, 25.05485, 25.05489,
+ 25.05492, 25.05495, 25.05496, 25.05499, 25.05501, 25.05503, 25.05506, 25.05508, 25.05511,
+ 25.05513, 25.05515, 25.05517, 25.05519, 25.0552, 25.05522, 25.05525, 25.05528, 25.0553,
+ 25.05531, 25.05532, 25.05534, 25.05536, 25.05538, 25.05541, 25.05543, 25.05546, 25.05548,
+ 25.05551, 25.05558, 25.05561, 25.05562, 25.05565, 25.05567, 25.0557, 25.05572, 25.05574,
+ 25.05576, 25.05578, 25.05579, 25.05582, 25.05582, 25.05583, 25.05584, 25.05585, 25.05586,
+ 25.05587, 25.05587, 25.05587, 25.05588, 25.05587, 25.05585, 25.05584, 25.05582, 25.05581,
+ 25.05579, 25.05577, 25.05576, 25.05575, 25.05575, 25.05575, 25.05576, 25.05578, 25.05579,
+ 25.0558, 25.05581, 25.05583, 25.05583, 25.05584, 25.05585, 25.05586, 25.05589, 25.05591,
+ 25.05593, 25.05596, 25.05599, 25.05603, 25.05605, 25.05608, 25.0561, 25.05614, 25.05619,
+ 25.05625, 25.0563, 25.05636, 25.05642, 25.05646, 25.05651, 25.05655, 25.0566, 25.05663,
+ 25.05667, 25.05671, 25.05675, 25.05679, 25.05683, 25.05687, 25.05691, 25.05695, 25.05699,
+ 25.05703, 25.05707, 25.05712, 25.05716, 25.05719, 25.05723, 25.05727, 25.05731, 25.05735,
+ 25.05739, 25.05743, 25.05747, 25.05751, 25.05757, 25.05763, 25.05769, 25.05774, 25.05779,
+ 25.05785, 25.0579, 25.05795, 25.05801, 25.05806, 25.05812, 25.05817, 25.05823, 25.05828,
+ 25.05834, 25.05839, 25.05844, 25.0585, 25.05855, 25.0586, 25.05866, 25.05871, 25.05876,
+ 25.05881, 25.05886, 25.0589, 25.05895, 25.059, 25.05905, 25.05911, 25.05917, 25.05922,
+ 25.05927, 25.05932, 25.05938, 25.05943, 25.05949, 25.05954, 25.0596, 25.05966, 25.05971,
+ 25.05977, 25.05983, 25.05989, 25.05994, 25.06, 25.06006, 25.06011, 25.06016, 25.06021,
+ 25.06027, 25.06033, 25.06038, 25.06042, 25.06048, 25.06054, 25.0606, 25.06066, 25.0607,
+ 25.06075, 25.0608, 25.06084, 25.06088, 25.06093, 25.06099, 25.06105, 25.06109, 25.06115,
+ 25.0612, 25.06125, 25.06129, 25.06134, 25.06139, 25.06144, 25.06149, 25.06153, 25.06158,
+ 25.06162, 25.06166, 25.06171, 25.06175, 25.0618, 25.06185, 25.0619, 25.06196, 25.06201,
+ 25.06206, 25.06211, 25.06215, 25.06219, 25.06224, 25.06228, 25.06232, 25.06237, 25.06242,
+ 25.06246, 25.06251, 25.06255, 25.06259, 25.06263, 25.06268, 25.06272, 25.06275, 25.06279,
+ 25.06282, 25.06285, 25.06288, 25.06291, 25.06293, 25.063, 25.06308, 25.06313, 25.06318,
+ 25.06323, 25.06327, 25.06332, 25.06336, 25.06341, 25.06346, 25.06351, 25.06356, 25.06362,
+ 25.06367, 25.06373, 25.06377, 25.06382, 25.06387, 25.06392, 25.06397, 25.06403, 25.06408,
+ 25.06414, 25.06419, 25.06423, 25.06431, 25.06435, 25.0644, 25.06446, 25.06451, 25.06456,
+ 25.06462, 25.06467, 25.06473, 25.06477, 25.06483, 25.06488, 25.06493, 25.06498, 25.06502,
+ 25.06507, 25.06512, 25.06516, 25.0652, 25.06525, 25.0653, 25.06535, 25.0654, 25.06546,
+ 25.0655, 25.06556, 25.06561, 25.06567, 25.06571, 25.06575, 25.0658, 25.06585, 25.06588,
+ 25.06592, 25.06595, 25.066, 25.06605, 25.0661, 25.06614, 25.06619, 25.06623, 25.06627,
+ 25.06632, 25.06638, 25.06644, 25.0665, 25.06655, 25.06662, 25.06668, 25.06674, 25.06681,
+ 25.06688, 25.06695, 25.06702, 25.06709, 25.06715, 25.06721, 25.06728, 25.06734, 25.06741,
+ 25.06749, 25.06755, 25.06762, 25.06767, 25.06774, 25.06779, 25.06786, 25.06793, 25.06799,
+ 25.06805, 25.06811, 25.06818, 25.06823, 25.06829, 25.06836, 25.06842, 25.06848, 25.06854,
+ 25.06861, 25.06868, 25.06874, 25.06881, 25.06888, 25.06896, 25.06903, 25.0691, 25.06916,
+ 25.06924, 25.06932, 25.0694, 25.06947, 25.06954, 25.06961, 25.06968, 25.06976, 25.06984,
+ 25.06991, 25.06998, 25.07006, 25.07014, 25.07022, 25.0703, 25.07037, 25.07044, 25.07052,
+ 25.07059, 25.07066, 25.07072, 25.07079, 25.07084, 25.07089, 25.07095, 25.07101, 25.07107,
+ 25.07112, 25.07119, 25.07126, 25.07132, 25.07138, 25.07144, 25.07151, 25.07158, 25.07165,
+ 25.07171, 25.07177, 25.07185, 25.07192, 25.07199, 25.07206, 25.07212, 25.07218, 25.07224,
+ 25.07228, 25.07234, 25.0724, 25.07246, 25.07253, 25.07259, 25.07265, 25.0727, 25.07277,
+ 25.07283, 25.07288, 25.07294, 25.073, 25.07304, 25.07309, 25.07314, 25.07319, 25.07323,
+ 25.07328, 25.07331, 25.07337, 25.07342, 25.07346, 25.0735, 25.07353, 25.07357, 25.07361,
+ 25.07366, 25.07371, 25.07374, 25.07377, 25.07379, 25.07382, 25.07385, 25.07387, 25.07391,
+ 25.07394, 25.07397, 25.074, 25.07402, 25.07404, 25.07407, 25.0741, 25.07412, 25.07414,
+ 25.07415, 25.07417, 25.07421, 25.07425, 25.07428, 25.07431, 25.07434, 25.07436, 25.07439,
+ 25.07442, 25.07446, 25.07449, 25.07453, 25.07457, 25.0746, 25.07463, 25.07466, 25.07469,
+ 25.07472, 25.07475, 25.07478, 25.07481, 25.07484, 25.07487, 25.0749, 25.07493, 25.07496,
+ 25.075) \ No newline at end of file
diff --git a/mapbox/src/main/java/com/example/mapbox/ui/MapboxMapView.kt b/mapbox/src/main/java/com/example/mapbox/ui/MapboxMapView.kt
new file mode 100644
index 0000000000..04fe3828cc
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/ui/MapboxMapView.kt
@@ -0,0 +1,282 @@
+package com.example.mapbox.ui
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.res.Resources
+import android.location.Location
+import android.view.Gravity
+import android.view.MotionEvent
+import android.view.View
+import com.example.mapbox.R
+import com.example.mapbox.breadcrumb.ExerciseEngineState
+import com.example.mapbox.extensions.getBitmapFromDrawable
+import com.example.mapbox.extensions.latLong
+import com.mapbox.mapboxsdk.camera.CameraPosition
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
+import com.mapbox.mapboxsdk.geometry.LatLng
+import com.mapbox.mapboxsdk.location.LocationComponentOptions
+import com.mapbox.mapboxsdk.location.OnCameraTrackingChangedListener
+import com.mapbox.mapboxsdk.location.OnLocationCameraTransitionListener
+import com.mapbox.mapboxsdk.location.OnLocationStaleListener
+import com.mapbox.mapboxsdk.location.modes.CameraMode
+import com.mapbox.mapboxsdk.location.modes.RenderMode
+import com.mapbox.mapboxsdk.maps.*
+import com.soy.android.maps.breadcrumb.Breadcrumb
+import com.soy.android.maps.compass.WassCompassEngine
+import com.soy.android.maps.extensions.getActivatedLocationComponent
+import com.soy.android.maps.extensions.isCameraInTrackingMode
+import timber.log.Timber
+import kotlin.math.roundToInt
+
+internal const val INITIAL_CAMERA_ZOOM_LEVEL_INDEX_WITH_LOCATION = 14
+/**
+ * Map is centered at Helsinki when we don't have user's current or any last location
+ */
+private const val DEFAULT_INITIAL_CAMERA_POSITION_LATITUDE = 60.1699
+private const val DEFAULT_INITIAL_CAMERA_POSITION_LONGITUDE = 24.9384
+
+private const val CAMERA_ANIMATION_DURATION = 200L
+
+internal fun buildCameraPosition(
+ target: LatLng = LatLng(DEFAULT_INITIAL_CAMERA_POSITION_LATITUDE, DEFAULT_INITIAL_CAMERA_POSITION_LONGITUDE),
+ zoomIndex: Int = INITIAL_CAMERA_ZOOM_LEVEL_INDEX_WITH_LOCATION
+) = CameraPosition.Builder().target(target).zoom(zoomIndex.toDouble()).build()
+
+/**
+ * [MapboxMapOptions] can either be applied via xml or programmatically when [MapView] is
+ * constructed. This function provides a predefined set of options.
+ */
+private fun createMapboxMapOptions(resources: Resources, location: Location?): MapboxMapOptions {
+ val cameraPosition = if (location == null) {
+ // Use default location and zoom level
+ buildCameraPosition()
+ } else {
+ buildCameraPosition(LatLng(location.latitude, location.longitude), INITIAL_CAMERA_ZOOM_LEVEL_INDEX_WITH_LOCATION)
+ }
+ return MapboxMapOptions().apply {
+ val compassImageTopMargin = resources.getDimension(R.dimen.size_spacing_xxsmall).roundToInt()
+ compassMargins(intArrayOf(0, compassImageTopMargin, 0, 0))
+ compassEnabled(true)
+ compassImage(resources.getDrawable(R.drawable.ic_shape_north_indicator, null))
+ compassGravity(Gravity.CENTER)
+ textureMode(true)
+ attributionEnabled(false)
+ logoEnabled(false)
+ zoomGesturesEnabled(true)
+ compassFadesWhenFacingNorth(false)
+ rotateGesturesEnabled(false)
+ camera(cameraPosition)
+ }
+}
+
+internal const val START_SYMBOL_ICON_ID = "id-start-icon"
+internal const val PAUSE_LINE_PATTERN = "id-stale-line-pattern"
+
+/**
+ * This class extends [MapView] and is suggested to use when creating map programmatically with a
+ * given cameraPosition which is used to center the camera on map. This view doesn't allow touch
+ * interactions for the child views of [MapView] such as compass, logo, attribute.
+ */
+@SuppressLint("ViewConstructor")
+class MapboxMapView(
+ context: Context,
+ location: Location? = null,
+ private val isBreadcrumbEnabled: Boolean = true
+) : MapView(context, createMapboxMapOptions(context.resources, location)), OnLocationStaleListener,
+ OnCameraTrackingChangedListener, MapboxMap.OnMapClickListener, OnMapReadyCallback, MapboxMap.OnMapLongClickListener {
+
+ init {
+ id = View.generateViewId()
+ }
+
+ private var map: MapboxMap? = null
+
+ private var breadcrumb: Breadcrumb? = null
+
+ private var exerciseEngineState = ExerciseEngineState.Recording
+
+ /**
+ * A boolean which keeps track of location stale status. Initially location is assigned to be stale since there is
+ * no gps fix at start up. The value changes in two places:
+ * 1- When [onStaleStateChange] is invoked, the value is updated based on the parameter
+ * 2- Whenever there is new gps fix it is set to be false
+ */
+ private var isLocationStale = true
+
+ internal var compassEngine: WassCompassEngine? = null
+ @CameraMode.Mode
+ private var lastCameraTrackingMode = CameraMode.TRACKING_COMPASS
+ private var cameraZoomLevelIndex = INITIAL_CAMERA_ZOOM_LEVEL_INDEX_WITH_LOCATION
+ private var isDefaultCameraPositionInUse = false
+
+ override fun onMapReady(mapboxMap: MapboxMap) {
+ map = mapboxMap.apply {
+ setStyle(Style.Builder()
+ .withImage(START_SYMBOL_ICON_ID, resources.getBitmapFromDrawable(R.drawable.ic_map_start_pin))
+ .withImage(PAUSE_LINE_PATTERN, resources.getBitmapFromDrawable(R.drawable.ic_stale_track_dot))
+ .fromUrl(context.getString(R.string.asoy_mapbox_style))
+ ) { style ->
+ startLocationComponent(mapboxMap, style)
+ if (isBreadcrumbEnabled) {
+ breadcrumb = Breadcrumb(this@MapboxMapView, mapboxMap, style)
+ }
+ }
+ addOnMapLongClickListener(this@MapboxMapView)
+ addOnMapClickListener(this@MapboxMapView)
+ }
+ }
+
+ // Location
+ @SuppressLint("MissingPermission")
+ private fun startLocationComponent(mapboxMap: MapboxMap, style: Style) {
+ mapboxMap.locationComponent.apply {
+ // Activate with options. If location engine is null, push location updates to
+ // the component without any internal engine management. No engine is going to
+ // be initialized and you can push location updates with
+ // [LocationComponent#forceLocationUpdate(Location)].
+ activateLocationComponent(
+ context,
+ style,
+ null,
+ LocationComponentOptions.createFromAttributes(context, R.style.mapbox_location)
+ )
+ compassEngine = this@MapboxMapView.compassEngine
+ addOnCameraTrackingChangedListener(this@MapboxMapView)
+ isLocationComponentEnabled = true
+ Timber.d("Mapbox Location Component is enabled")
+ addOnLocationStaleListener(this@MapboxMapView)
+ renderMode = RenderMode.GPS
+ cameraMode = lastCameraTrackingMode
+ }
+ }
+
+ internal fun onNewLocation(location: Location) {
+ isLocationStale = false
+ map?.run {
+ getActivatedLocationComponent()?.run {
+ if (isDefaultCameraPositionInUse) {
+ updateMapCameraZoom(INITIAL_CAMERA_ZOOM_LEVEL_INDEX_WITH_LOCATION)
+ isDefaultCameraPositionInUse = false
+ }
+ forceLocationUpdate(location)
+ breadcrumb?.onNewLocation(location.latLong(), exerciseEngineState)
+ }
+ }
+ }
+
+ override fun onStaleStateChange(isStale: Boolean) {
+ Timber.d("Location stale state change. Is Stale: $isStale")
+ isLocationStale = isStale
+ map?.getActivatedLocationComponent()?.run {
+ renderMode = if (isStale) RenderMode.NORMAL else RenderMode.GPS
+ val locationComponentStyle = if (isStale) R.style.mapbox_stale_location else R.style.mapbox_location
+ applyStyle(LocationComponentOptions.createFromAttributes(context, locationComponentStyle))
+ }
+ }
+
+ // Camera
+ private fun updateMapCameraZoom(zoomLevelIndex: Int) = map?.getActivatedLocationComponent()?.run {
+ cameraZoomLevelIndex = zoomLevelIndex
+ if (cameraMode != CameraMode.NONE) {
+ zoomWhileTracking(getCameraZoomLevel(), CAMERA_ANIMATION_DURATION)
+ } else {
+ map?.easeCamera(CameraUpdateFactory.zoomTo(getCameraZoomLevel()))
+ }
+ }
+
+ private fun getCameraZoomLevel(): Double = map?.cameraPosition?.zoom ?: 0.0
+
+ override fun onCameraTrackingChanged(currentMode: Int) {
+ Timber.d("Camera tracking mode changed. Current mode: $currentMode")
+ if (map?.isCameraInTrackingMode() == true) {
+ lastCameraTrackingMode = currentMode
+ }
+ }
+
+ /**
+ * Invoked whenever camera tracking is broken.
+ */
+ override fun onCameraTrackingDismissed() {
+ Timber.d("Exiting from camera tracking mode")
+ updateCameraMode(CameraMode.NONE_COMPASS)
+ }
+
+ private fun updateCameraMode(@CameraMode.Mode mode: Int) {
+ // We need to
+ map?.getActivatedLocationComponent()?.apply {
+ if (cameraMode != CameraMode.NONE) {
+ setCameraMode(mode, object : OnLocationCameraTransitionListener {
+ override fun onLocationCameraTransitionFinished(cameraMode: Int) {
+ zoomWhileTracking(getCameraZoomLevel(), CAMERA_ANIMATION_DURATION)
+ }
+
+ override fun onLocationCameraTransitionCanceled(cameraMode: Int) {
+ // No impl.
+ }
+ })
+ } else {
+ cameraMode = mode
+ }
+ }
+ }
+
+ // Gestures
+ /**
+ * When [MapboxMap.OnMapClickListener.onMapClick] is called camera mode is updated:
+ * There are two camera tracking modes enabled:
+ * The [CameraMode.TRACKING_GPS_NORTH] sets the camera always to the north and the [CameraMode.TRACKING_COMPASS]
+ * sets the location indicator to north and map rotates according to heading
+ * If camera mode is [CameraMode.TRACKING_GPS_NORTH], onClick switches the mode to [CameraMode.TRACKING_COMPASS]
+ * If camera mode is [CameraMode.TRACKING_COMPASS] onClick switches the mode to [CameraMode.TRACKING_GPS_NORTH]
+ * If user starts panning while in tracking mode, camera switches to [CameraMode.NONE_COMPASS] mode and user is not
+ * tracked by camera. On click switches the camera back to last used tracking mode
+ */
+ override fun onMapClick(point: LatLng): Boolean {
+ map?.getActivatedLocationComponent()?.apply {
+ when (cameraMode) {
+ CameraMode.TRACKING_GPS_NORTH -> updateCameraMode(CameraMode.TRACKING_COMPASS)
+ CameraMode.TRACKING_COMPASS -> updateCameraMode(CameraMode.TRACKING_GPS_NORTH)
+ CameraMode.NONE_COMPASS,
+ CameraMode.NONE,
+ CameraMode.NONE_GPS -> updateCameraMode(lastCameraTrackingMode)
+ else -> Timber.w("Using unsupported camera mode")
+ }
+ }
+ return true
+ }
+
+ /**
+ * Used for mocking exercise pause / resmume controls
+ */
+ override fun onMapLongClick(point: LatLng): Boolean {
+ if (exerciseEngineState == ExerciseEngineState.Paused) {
+ exerciseEngineState = ExerciseEngineState.Recording
+ } else if (exerciseEngineState == ExerciseEngineState.Recording) {
+ exerciseEngineState = ExerciseEngineState.Paused
+ }
+ return true
+ }
+
+ /**
+ * By overriding this method, we prevent compass view component of the [MapView] from consuming the clicks
+ */
+ override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
+ super.onInterceptTouchEvent(ev)
+ return true
+ }
+
+ override fun onResume() {
+ super.onResume()
+ breadcrumb?.onResume()
+ }
+
+ override fun onStop() {
+ breadcrumb?.onStop()
+ super.onStop()
+ }
+
+ override fun onDestroy() {
+ breadcrumb?.onDestroy()
+ super.onDestroy()
+ }
+}
diff --git a/mapbox/src/main/java/com/example/mapbox/ui/extensions/ConstraintLayoutExtensions.kt b/mapbox/src/main/java/com/example/mapbox/ui/extensions/ConstraintLayoutExtensions.kt
new file mode 100644
index 0000000000..84fa569e1b
--- /dev/null
+++ b/mapbox/src/main/java/com/example/mapbox/ui/extensions/ConstraintLayoutExtensions.kt
@@ -0,0 +1,19 @@
+package com.example.mapbox.ui.extensions
+
+import android.support.constraint.ConstraintLayout
+import android.support.constraint.ConstraintSet
+import android.view.View
+
+fun ConstraintLayout.addViewAndMatchItToParent(view: View, zIndex: Int = 0) {
+ addView(view, zIndex)
+ ConstraintSet().run {
+ clone(this@addViewAndMatchItToParent)
+ view.run {
+ connect(id, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP)
+ connect(id, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START)
+ connect(id, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END)
+ connect(id, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM)
+ }
+ applyTo(this@addViewAndMatchItToParent)
+ }
+}