Skip to content

Android SDK ​

mn.dock:dock-android 0.65.0, Kotlin. Java 8 bytecode, Android API 21 болон түүнээс дээш. Хоёр сан шаардана, хоёулаа Android-д түгээмэл: kotlinx-coroutines, kotlinx-serialization. Хайлт, цэгээр хайлт, барилгын код, хаалга хүртэлх зам, газрыг id-гаар, өөрчлөлт, хаалганы мэдэгдэл, жолоочийн баталгаа, хэрэглээ, хайлтын мэдээлэл хуваалцах, аялал бичих. JS SDK, iOS SDK-тэй ижил дуудлага, нэр, алдаа. Түлхүүрийг нэг client хадгална. Анхны хувилбар: газрын зураг хараахан байхгүй.

Суулгах ​

Maven Central дээр хараахан гараагүй. Гартал Maven репозиторийн хавтсыг (sdk/android дотор ./gradlew publish үүнийг build/repo-д бичнэ) холбогч хүнээсээ аваад төсөлдөө dock-repo/ нэрээр хийж, репозиторийн жагсаалтад нэмнэ. SDK-ийн POM kotlinx-coroutines, kotlinx-serialization-ийг өөрөө авчирдаг тул апп ганц мөр нэмнэ:

kotlin
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("dock-repo") }
    }
}
kotlin
dependencies {
    implementation("mn.dock:dock-android:0.65.0")
}

Maven Central дээр гарсны дараа dock-repo мөрийг хасна; хамаарлын мөр хэвээрээ.

Client ​

kotlin
import mn.dock.*

val dock = Client("dk_...")

Түлхүүр dk_ ба 32 тэмдэгт биш бол constructor нь DockError invalid_key шиднэ. baseUrl анхдагчаар https://geo.dock.mn. Дуудлага бүр suspend функц. Coroutine дотроос дуудна (lifecycleScope.launch { ... }); сүлжээний хэсэг Dispatchers.IO дээр ажиллана.

Хайлт, цэгээр хайлт, барилгын код ​

kotlin
val found = dock.geocode("Сансар 24", limit = 5)
for (place in found.results) {
    println(label(place, Lang.MN))
}

val typing = dock.geocode("Сан", proximity = LonLat(106.9177, 47.9186))
println("${typing.results.size} results")
val streets = dock.geocode("Сансар", types = listOf(GeocodeType.STREET, GeocodeType.AREA))
println("${streets.results.size} streets")

val here = dock.reverse(LonLat(106.9301, 47.9201), radius = 50.0)
println("${here.districtMn ?: "?"} ${here.results.size}")
val landmarks = dock.reverse(LonLat(106.9301, 47.9201), radius = 300.0, types = listOf(ReverseType.LANDMARK))
println("${landmarks.results.size} landmarks")

when (val typed = parseDoorCode("7qsvх 17")) {
    is DoorCodeInput.Code -> println(label(dock.door(typed.code, unit = typed.unit), Lang.MN))
    is DoorCodeInput.Invalid -> println(typed.error.name)
}
doorLink("7qsvх", "17")?.let { println(it) }
val opened = parseDoorLink("https://map.dock.mn/d/7QSVX?u=17")
if (opened is DoorCodeInput.Code) println(opened.code + " " + (opened.unit ?: "-"))
doorQr("7qsvх", "17")?.let { println(it.size.toString()) }
val qrSvg = doorQrSvg("7qsvх", "17")
doorQrPixels("7qsvх", "17")?.let { println(it.side.toString()) }

Цэг нь LonLat(lon, lat), эхлээд уртраг, API-тай адил. Барилгын код кирилл ижил хэлбэртэй үсгийг (К, М, Т, Х, Р, С, В, Н) хүлээж авна. Хаалга, газрыг хүнд үргэлж label(place, lang)-ээр харуулна, Lang.MN эсвэл Lang.EN. Ярианы хэлбэр, дараа нь нэр, дараа нь бүтэн хаяг, дараа нь кодыг сонгоно. Албан ёсны хаягтай таараагүй бүх зүйлийн ард "(албан бус)" гэж нэмнэ, API үүнийг шаарддаг. Id нь дуудлагад зориулсан, хүнд хаяг болгож хэзээ ч харуулахгүй. Орон сууц, оффисын төрөл нь DoorUnit (JS, Swift-д Unit), ингэснээр Kotlin-ий Unit-ийг далдлахгүй.

Хүн бичих зуур proximity-д хүн байгаа газар эсвэл газрын зургийн төвийг өг: бичсэн үгээр ижил таарцтай эхэлсэн нэрсээс ойр газар нь эхэнд гарна. Цэг зөвхөн тэр хүсэлттэй явна. Төхөөрөмж дээр хадгалагдахгүй, API бичихгүй, хайлт хуваалцахад явахгүй. Сүлжээгүй үеийн хариу үүнийг уншихгүй.

parseDoorCode(text) бичсэн эсвэл буулгасан кодыг API-тай адил уншина, хүсэлт явуулахгүй: DoorCodeInput.Code(code, unit), эсвэл DoorCodeInput.Invalid(error, reason). error нь EMPTY, LENGTH (5 тэмдэгт биш) эсвэл LETTERS (эгшиг, I, L, O, U, эсвэл тэмдэг). Хүн бичих зуур талбарыг шалгаж, error бүрт өөрийн үгээ харуул. door(code, unit) ийм бичвэрийг хүсэлт явуулахаас өмнө мөн адил татгалзана: DockError 400 invalid_code.

doorLink(text, unit) хаалгыг хуваалцах холбоос үүсгэнэ: https://map.dock.mn/d/7QSVX?u=17. Хуваалцах цонх, мессеж эсвэл QR-д хэрэглэнэ. Бичвэр код болж чадахгүй бол null. Хүсэлт явуулахгүй, тэр кодтой хаалга байгаа эсэхийг шалгахгүй. parseDoorLink(text) бичвэр дэх эхний хаалганы холбоосыг уншина: буулгасан мессеж, эсвэл апп-ыг нээсэн холбоосын URL. Холбоос байхгүй бол null, байвал parseDoorCode-той ижил хариу. Хаягийн талбар буулгасан холбоосыг зөвхөн түүний хаалгаар хайна. map.dock.mn хаалганы хуудсыг одоогоор үзүүлэхгүй; холбоосыг бүх SDK одоо уншина.

doorQrPixels(text, unit, px, margin) хаалганы QR-ыг ARGB пиксел болгоно: дотор нь doorLink-ийн холбоос, хар цагаан, Bitmap.createBitmap(qr.argb, qr.side, qr.side, Bitmap.Config.ARGB_8888), хуваалцах цонх эсвэл хэвлэхэд. Утасны камер мессежийн холбоостой ижил холбоосыг нээнэ. Модуль бүр px пиксел (анхдагч 8), эргэн тойронд margin цагаан модуль (анхдагч 4, стандартын доод хэмжээ). doorQrSvg(text, unit, px, margin) ижил QR-ыг SVG бичвэр болгоно (px анхдагч 4.0), doorQr(text, unit) модулиудыг өгнө (modules[y][x] бараан бол true, size, version), Canvas дээр өөрөө зурахад. ISO/IEC 18004, алдааны засвар M (15%), JS, Swift SDK-тай ижил модуль. Сүлжээгүй, сан шаардахгүй. Бичвэр код болж чадахгүй бол null. px, margin хүрээнээс гарвал IllegalArgumentException.

Зам ​

kotlin
val trip = dock.route(Client.End.Point(LonLat(106.9177, 47.9186)), Client.End.Code("7QSVX"), RouteMode.DRIVING)
println("${trip.distanceM} м, ${trip.durationS} с, алхах ${trip.to.gapM} м")
trip.to.door?.let { println(label(it, Lang.MN)) }

from, to тус бүр Client.End.Point эсвэл Client.End.Code. Хаалганы код хаалга руу чиглүүлнэ. Барилга, хашааны код өгвөл газрын зурагт хаалга нь байвал хаалганд, байхгүй бол гудамжны талд дуусна: замын шугамын төгсгөлд хамгийн ойр барилга, хашааны хүрээний цэг. to.point нь тэр төгсгөл, to.unit.streetSide нь хаалга, эсвэл гудамжны цэгээс 25 м-ийн дотор бол true. Алхах зай 15 м-ээс урт бол сүүлчийн алхам "Машинаа тавиад 17 м алхана уу." гэж хэлнэ, ирэлт "Хаалга зүүн талд байна" гэж хаалга, түүний талыг хэлнэ. RouteMode.DRIVING, WALKING, CYCLING. Үлдсэн шулуун алхалт to.gapM метр. route:read, код бол door:read хэрэгтэй. durationS нь түгжрэлгүй хугацаа; машины маршрут measured-тэй (API 0.48.0): нийтэлсэн хурдтай замыг (traceRoads) тэр хурдаар тооцсон durationS, ийм замын метр roadsM; явган, дугуйд null. departAt (API 0.50.0, java.util.Date) өгвөл тэр цагийн бүсийн хурдыг уншиж, measured.band-д бүсээ хэлнэ ("am_peak", "pm_peak", "off_peak"); өгөхгүй бол бүх цаг, band нь null. to кодоор өгсөн бол to.door нь тэр хаалга, цэг бол null; label(place, lang)-ээр харуулна.

via (API 0.67.0) нь замдаа дайрах ROUTE_VIA_MAX (10) хүртэл төгсгөл, өгсөн дарааллаар, тус бүр цэг эсвэл код, Mapbox-ын эхний ба сүүлчийн хоорондох waypoint шиг. legs нь хэсэг бүрийн distanceM, durationS, via нь дайрах төгсгөл бүрийг маршрутын төгсгөл хэлбэрээр, шугам дайрсан газар нь snapped. Шугам дайрах цэг дээр буцаж эргэж болно. Хоосон жагсаалт бол байхгүйтэй адил; илүү урт, эсвэл ; агуулсан код бол хүсэлт явуулахаас өмнө DockErrorinvalid_via шиднэ.

Матриц ​

kotlin
val couriers = listOf(Client.End.Point(LonLat(106.9177, 47.9186)), Client.End.Point(LonLat(106.9050, 47.9210)))
val times = dock.matrix(couriers, listOf(Client.End.Code("7QSVX"), Client.End.Point(LonLat(106.9301, 47.9201))))
// Seconds from each courier to the first stop; null where no road joins them.
val toFirst = times.durationsS.map { it[0] ?: Double.POSITIVE_INFINITY }
val nearest = toFirst.indexOf(toFirst.min())
println("хамгийн ойр $nearest, ${toFirst[nearest]} с")

matrix(from, to, mode) (API 0.63.0) нь from-ын төгсгөл бүрээс to-ын төгсгөл бүр хүртэлх түгжрэлгүй хугацаа, зайг нэг дуудлагаар өгнө; хамгийн ойр курьерыг сонгох диспетчерт. Жагсаалт бүр 1-ээс MATRIX_MAX (10) төгсгөлтэй, төгсгөл бүр route-ынх шиг. durationsS[i][j], distancesM[i][j] нь from[i]-ээс to[j] хүртэл; хооронд нь зам холбохгүй бол null. from, to нь gapM-тэйгээ маршрутын төгсгөл болж буцна. measured, departAt, шугам байхгүй: сонгосноо route-аар асууна. Зам хаалтыг маршрутынх шиг тойрно. route:read, код ашиглавал door:read эрх. Хоосон эсвэл урт жагсаалт, ; агуулсан кодыг хүсэлт илгээхээс өмнө 400 invalid_from эсвэл invalid_to-оор татгалзана. Хаалга биш код 404 not_found, байрлалаараа (to[1]) нэрлэгдэнэ. Нүдний тооноос үл хамааран нэг дуудлага. Хамрах хүрээ: Улаанбаатар.

Хүрэх бүс ​

kotlin
val zone = dock.isochrone(Client.End.Point(LonLat(106.9177, 47.9186)), listOf(10, 20, 30))
// The largest first; each feature holds one or more polygons of [lon, lat] rings.
for (f in zone.features) println("${f.properties.contour} минут, хэсэг ${f.geometry.polygons.size}")

isochrone(from, contoursMinutes, mode) (API 0.64.0) нь нэг төгсгөлөөс 1-ээс ISOCHRONE_CONTOURS_MAX (4) хугацаа бүрт хүрэх талбайг өгнө; хугацаа нь 1-ээс ISOCHRONE_MINUTES_MAX (60) хүртэлх бүхэл минут, өсөх дарааллаар: дэлгүүр, агуулахын хүргэлтийн бүс. from нь route-ынх шиг барилгын код (хаалгаас нь) эсвэл цэг. Хариу нь GeoJSON: contour бүрт нэг feature, хамгийн томоос нь эхэлнэ, properties.contour минут, geometry нь IsochroneGeometry: Polygon, талбай хэсэг хэсэг бол MultiPolygon. geometry.polygons хэсэг бүрийг цагирагуудаар нь, гадна талынхыг эхэнд өгнө, бүгдийг адил будна; Isochrone.serializer()-ээр буцааж encode хийвэл хариу дахин GeoJSON болж MapLibre-ийн GeoJSON source-д орно. from нь gapM-тэйгээ маршрутын төгсгөл болж буцна. Түгжрэлгүй хурдаар, departAt байхгүй; зам хаалтыг маршрутынх шиг тойрно. route:read, код ашиглавал door:read эрх. Өөр хугацааг хүсэлт илгээхээс өмнө 400 invalid_contours-оор татгалзана. Ойр зам байхгүй цэг 422 no_route. Contour-ын тооноос үл хамааран нэг дуудлага. Хамрах хүрээ: Улаанбаатар.

Замд буулгах ​

kotlin
val trip = dock.matching(
    listOf(LonLat(106.9177, 47.9186), LonLat(106.92, 47.9188), LonLat(106.923, 47.919)),
    timestamps = listOf(1790000000L, 1790000030L, 1790000060L),
)
// One matching per unbroken piece, each a line of [lon, lat]; a tracepoint is null where no road was found.
for (m in trip.matchings) println("${m.distanceM.toInt()} м, ${m.geometry.coordinates.size} цэг")

matching(coordinates, timestamps, mode) (API 0.65.0) нь GPS мөрийг явсан замууд дээр нь буулгана: түүхий цэгүүд тахир муруй байхад шуудан зөөгчийн аяллыг замаар нь өгнө. coordinates нь бичигдсэн дарааллаар 2-оос MATCHING_MAX (100) цэг; timestamps заавал биш, цэг бүрт нэг бүхэл Unix секунд, буцахгүй; түүгээр хэдхэн секундын зайтай хол хоёр цэг хурдан зам биш, тасалдал гэж уншигдана. Хариунд matchings: тасраагүй хэсэг бүрт нэг (distanceM, эргэлтийн зардалгүй чөлөөт урсгалын хурдаар durationS, geometry нь LineString), tracepoints: цэг бүрт дарааллаараа нэг MatchTracepoint (matchingsIndex, location, gapM), зам олдоогүй эсвэл хязгаарлалттай газар доторх цэгт null. Хаалттай замыг тойрохгүй: мөр нь хүний явсан газар. Мөрийг хадгалахгүй, логт бичихгүй; аяллаа газрын зурагт өгөх бол startTrace. route:read эрх. Өөр тоо, хугацааг хүсэлт илгээхээс өмнө 400 invalid_coordinates эсвэл invalid_timestamps-оор татгалзана. Мөрийн ойролцоо зам байхгүй бол 422 no_match; хязгаарлалттай газраас гадна 2-оос цөөн цэг үлдвэл 422 not_accepted. Нэг дуудлага. Хамрах хүрээ: Улаанбаатар.

Зогсоолуудын дараалал ​

kotlin
val round = dock.optimizedTrips(
    listOf(
        Client.End.Point(LonLat(106.9177, 47.9186)), Client.End.Code("7QSVX"),
        Client.End.Point(LonLat(106.905, 47.921)), Client.End.Point(LonLat(106.925, 47.915)),
    ),
)
// The stops in the order to drive them, each by its place in the list sent.
val order = round.waypoints.indices.sortedBy { round.waypoints[it].waypointIndex }
println("$order, ${round.trips[0].distanceM.toInt()} м, ${round.trips[0].durationS.toInt()} с")

optimizedTrips(stops, roundtrip, mode) (API 0.66.0) нь зогсоолуудыг замд хамгийн бага хугацаа зарцуулах дарааллаар тавьж, тэр дарааллаарх аяллыг өгнө: шуудан зөөгчийн өдрийн тойрог нэг дуудлагаар. stops нь 2-оос OPTIMIZED_TRIPS_MAX (12) төгсгөл, тус бүр барилгын код (хаалга хүртэл) эсвэл цэг, route шиг. Аялал эхнийхээс эхэлнэ. roundtrip анхдагчаар true: эхнийх рүүгээ буцна; false бол илгээсэн сүүлийнхээр дуусна. Хариунд trips: нэг Trip (distanceM, чөлөөт урсгалын хурдаар durationS, geometry нь LineString, legs нь зогсоол хоорондын хэсэг бүрт нэг TripLeg), waypoints: илгээсэн дарааллаар зогсоол бүрт нэг TripWaypoint, маршрутын төгсгөл шиг, waypointIndex нь аялал дахь байрлал. Өнөөдрийн хаалтыг тойрно. Зогсоол дээрх хугацааг тооцохгүй. route:read эрх, код бол door:read. Цөөн эсвэл олон зогсоол, ; агуулсан кодыг хүсэлт илгээхээс өмнө 400 invalid_coordinates-оор татгалзана. Ямар ч зам хүрэхгүй зогсоол 422 no_route; 404 not_found зогсоолыг байрлалаар нь нэрлэнэ (coordinates[1]: ...). Нэг дуудлага. Хамрах хүрээ: Улаанбаатар.

Цэг дээрх объект ​

kotlin
val tapped = dock.tilequery(LonLat(106.9177, 47.9186), radius = 30.0, limit = 10)
// Nearest first: the building the point is in, then the entrances within 30 m.
for (f in tapped.features) println("${f.properties.tilequery.layer} ${f.properties.tilequery.distance} m")

entrancesNear(point, radius, limit) цэгийн хамгийн ойрын барилгын батлагдсан хаалгуудыг өгнө (API 0.85.0): газрын зураг дээр удаан дарахад. Ойроосоо эхэлж, бүр нь барилга, distance_m-тэй. Барилгын эзэн эсвэл СӨХ батлаагүй бол жагсаалт хоосон. radius метрээр, өгөөгүй бол 50, дээд тал нь 1000; limit өгөөгүй бол 1, дээд тал нь 20. geocode:read шаардана.

venue(venueId), venueLevel(venueId, level), venueSpot(venueId, unitId), venueRoute(venueId, from, unitId, fromLevel), venueDirections(venueId, from, unitId, mode) барилгын дотоод зургийг өгнө: давхрууд (ordinal 0 газар, -1 хонгил), нэг давхрын өрөө, нүх, үйлчилгээ (бүр нь source, confidence-тэй), хэвлэсэн самбар юу гэж хэлэхийг, дотор нэг өрөө хүртэлх явган замыг (монгол алхмууд, давхар бүрийг заасан), мөн зөв гудамжны орц хүртэлх зам, түүнээс цааших явган замыг. Venue id-г geocode мөрийн indoor.venue_id-аас авна. Нэр, талбар нь JS SDK-тай адил. venue, venueLevel, venueSpot, venueRoute door:read, venueDirections route:read шаардана. Үл мэдэгдэх барилга, давхар, өрөө 404 not_found; коридор зурагдаагүй бол 422 no_route. Юуг ч зохиохгүй.

tilequery(point, sources, radius, limit, geometry) (API 0.68.0) нь цэг дээрх эсвэл ойрхон байгаа байшин, хаалгыг өгнө, Mapbox-ын Tilequery API шиг: газрын зураг дээр дарсан газарт юу байгааг. sources анхдагчаар TilequerySource-ын хоёр утга, эсвэл аль нэг нь. radius метрээр, 0-ээс TILEQUERY_RADIUS_MAX_M (1000), сантиметр хүртэл илгээнэ; өгөхгүй бол API зөвхөн цэг дотор нь байгаа байшинг олно, хаалганд radius хэрэгтэй. limit 1-ээс TILEQUERY_LIMIT_MAX (50), анхдагч 5. geometry (TilequeryGeometry) нэг төрлийг үлдээнэ. Хариу нь GeoJSON, хамгийн ойроос нь: объект бүр Point, илгээсэн цэгт хамгийн ойрх хэсэг нь, тайлын талбаруудтайгаа (байшингийн nameMn, type, levels; хаалганы kind, letter), tilequery: distance метрээр (дотор нь бол 0), geometry, layer. Тайлтай ижил мөр, барилгын код үгүй: кодыг door(code) авна. Эрх tiles:read; тайлын хязгаарт биш, rate_limit, daily_quota-д тооцно. API-ын татгалзах бүхнийг хүсэлт илгээхээс өмнө түүний алдаагаар татгалзана: эх үүсвэрт 404 not_found, 400 invalid_point, invalid_radius, invalid_limit. Хамрах хүрээ: Улаанбаатар.

Ойрын газрууд ​

kotlin
val near = dock.nearby(LonLat(106.9177, 47.9186), listOf(NearbyCategory.PHARMACY, NearbyCategory.BANK), radius = 1500.0, limit = 20)
// Nearest first. A store has no code: say so, and show its official address.
for (place in near.results) {
    val code = place.code ?: "код алга"
    println("${place.category} ${place.distanceM.toInt()} м $code")
}

nearby(point, categories, radius, limit) цэгийн ойрын газрыг ангиллаар нь, ойроос нь өгнө, бүрт category, distanceM: хайлтын талбарын доорх товчнууд. "Хоол" товч бол listOf(NearbyCategory.RESTAURANT, NearbyCategory.CAFE). radius анхдагч 1000 м, 10000 хүртэл; limit анхдагч 10, 20 хүртэл. Ангилал бүрийг нэг удаа, өгсөн дарааллаар илгээнэ. Банк, шатахуун, эмийн сан, хоол, кафе, дэлгүүр зөвхөн улсын бүртгэлтэй таарсан бизнес, таарах хүртэл хоосон. Бүртгэлтэй сүлжээний дэлгүүр code null: хаалга нь тодорхойгүй тул "код алга" ба officialAddress-ийг, байрлах барилгынх нь, харуулна. Автобусны буудал хотын чиглэлүүдээ lines-д авна. Хоосон жагсаалтыг хүсэлт явуулахаас өмнө DockError 400 invalid_category-оор татгалзана. Эрх geocode:read.

Зам хаалт ​

kotlin
val closures = dock.closures()
val avoid = excludePolygons(closures, "2026-10-05")
println("${closures.current} хаалт, тухайн өдөр ${avoid.ids.size}, ${avoid.rings.size} хүрээ")
println(avoid.closureAt(LonLat(106.9303, 47.9202)) ?: "хаалган дээр хаалт алга")

Түншүүдийн мэдэгдсэн зам хаалт (үер, угаагдсан зам, гүүр эвдэрсэн, цас, шавар, засвар). Өнөөдөр дуусаагүй бүгд, тус бүр тойрсон хүрээтэй. Түншийн нэр, тэмдэглэл ирэхгүй. Итгэлцүүр 0.5: нэг түншийн үг. Хариуг утсанд хадгална: офлайн багцын closures хэсэгтэй ижил хэлбэртэй. excludePolygons(closures, day) офлайн ажиллана: аяллын өдөр идэвхтэй хаалтыг үлдээж (from <= day, to байвал day <= to; анхдагч нь өнөөдөр, Улаанбаатарын цагаар) тэдгээрийн хүрээг өөрийн Valhalla-ийн exclude_polygons-д өгнө. Нэг хүсэлтэд Valhalla-ийн хязгаараас (10,000 м хүрээ, 100 орой) хэтэрвэл ClosuresOverLimitException шиднэ: замыг татгалз, хаалтыг бүү хая. asOf-оос өмнөх өдөр IllegalArgumentException шиднэ: дахин татаж ав. Хаалт нэмэгдэх эсвэл цуцлагдахад idsSha256 өөрчлөгдөнө. avoid.closureAt(point) аяллын эхлэл эсвэл төгсгөлийг агуулсан хаалтын id-г өгнө, үгүй бол null: Valhalla хүрээн доторх бүх замыг хасдаг тул тэнд эхлэх, дуусах зам байхгүй, таны Valhalla "No path could be found for input" гэж хариулна. Хоёр үзүүрийг эхлээд шалга. GET /v1/route өнөөдрийн хаалтыг өөрөө тойрч, closures.avoided-д нэрлэнэ, хаалтын доторх үзүүрийг 422 end_in_closure-ээр татгалзана. route:read эрх.

Зам хаалт мэдэгдэх ​

kotlin
val retryKey = java.util.UUID.randomUUID().toString()
val report = dock.reportClosure(
    ClosureReport(ClosureGeometry.Point(LonLat(106.9303, 47.9202)), ClosureKind.FLOOD, to = "2026-10-09", note = "Гарц 1 м усан дор"),
    idempotencyKey = retryKey,
)
val until = report.properties.to ?: "цуцлах хүртэл"
println("${report.id} ${report.properties.from} $until")
val mine = dock.closure(report.id)
println(mine.properties.note)
val opened = dock.liftClosure(report.id)
println(opened.properties.lifted ?: "цуцлаагүй")

reportClosure(report, idempotencyKey) нь замын хэсэг эсвэл гарцаар явах боломжгүйг dock-д мэдэгдэнэ. kind нь FLOOD, WASHOUT, BRIDGE_OUT, SNOW, MUD, WORKS, OTHER-ийн нэг; geometry нь замын хэсэг дээрх ClosureGeometry.Point (уулзвар дээр биш), эсвэл 3000 м-ээс ихгүй ClosureGeometry.LineString. from нь хаалттай эхний өдөр, null бол өнөөдөр; to нь сүүлийн өдөр, null бол цуцлах хүртэл. Мэдэгдэл үүрд хадгалагдана, засагдахгүй, устахгүй. dock дээрх зам түүнийг from өдрөөс тойрно, closures() бүх түншид таны нэр, тэмдэглэлгүйгээр өгнө. Итгэлцүүр 0.5: нэг түншийн үг. Мэдэгдэл бүрт өөрийн idempotencyKey өгч (UUID.randomUUID() тохирно), хариу иртэл хадгал: хугацаа хэтэрсний дараа ижил түлхүүр, ижил мэдэгдлээр дахин илгээвэл эхний мэдэгдэл буцаж ирнэ, хоёр удаа хадгалагдахгүй. Ижил түлхүүрээр өөр мэдэгдэл илгээвэл 422 idempotency_key_reused. API-ийн татгалзах түлхүүр (үсэг, тоо, ._:--ээс 1-64 тэмдэгт, IDEMPOTENCY_KEY_RE) хүсэлт явахаас өмнө DockError bad_idempotency_key шиднэ. Тэмдэглэлд дараалсан 6 цифр байвал 400 note_has_phone: утасны дугааргүй. Хязгаарлалттай газар дотор 400 restricted. closure(id) нь өөрийн мэдэгдлийг тэмдэглэлтэй нь уншина: таны экспорт. liftClosure(id, on) нь замыг on өдрөөс дахин нээнэ, null бол өнөөдөр, хойших өдөр болохгүй (400 lift_in_future); мэдэгдэл үлдэж, lifted нэг удаа тавигдана. Бусад байгууллагын id 404 not_found. Гурвуулаа closures:write эрх шаардана.

Багцын файл шалгах, офлайн ​

kotlin
import java.io.File

// In an app: File(packDir, "manifest.json").readText()
val manifest = PackManifestFiles.fromJson("""
{"files":[{"name":"pois.geojson","bytes":2,"sha256":"44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"},
 {"name":"water.geojson","bytes":265463,"sha256":"e9973b42c4b0e6827348e501acd798a1fff25206f4b67708b5f06179e3f6c199"}]}
""")
// In an app: the folder the pack was downloaded to
val packDir = File(System.getProperty("java.io.tmpdir"), "dock-pack-" + System.nanoTime()).apply { mkdirs() }
File(packDir, "pois.geojson").writeText("{}")
val check = checkPack(manifest, packDir)
for (f in check.files) println("${f.name} ${f.status}")
println("ok ${check.ok} bad ${check.bad.joinToString(" ")}")

manifest нь багцын manifest.json; зөвхөн files мөрүүдийг уншина: багцын хавтас дахь файл бүрийн нэр, хэмжээ, sha256 (одоогийн багцад tiles.tar, crossings.geojson, pois.geojson, basemap.pmtiles, wetlands.geojson, passes.geojson, sand.geojson, water.geojson). checkPack(manifest, directory) нь directory дахь жагсаасан файл бүрийг manifest-ийн дарааллаар эхлээд хэмжээгээр, дараа нь sha256-аар 1 MB-аар уншиж шалгана. status нь OK, MISSING (файл алга, эсвэл тэр нэртэй хавтас), BYTES (хэмжээ өөр, жишээ нь таслагдсан татан авалт; hash бодохгүй) эсвэл SHA256 (хэмжээ ижил, агуулга өөр). Жагсаасан бүх файл OK үед л ok нь true. bad бусдыг нэрлэнэ: тэдгээрийг дахин тат, ok болтол багцаас нэг ч файл бүү хэрэглэ. manifest-д жагсаагаагүй файлыг уншихгүй. Файлгүй manifest, энгийн файлын нэр биш нэр (хавтас, .., цэгээр эхэлсэн), хоёр удаа жагсаасан нэр, сөрөг bytes, 64 жижиг үсгийн hex биш sha256 нь ямар ч файл уншихаас өмнө IllegalArgumentException шиднэ: сүлжээнээс ирсэн manifest багцын хавтсаас гадуурх файлыг нэрлэж чадахгүй. hash бодох хооронд зогсоно (суурь газрын зураг 113 MB): Dispatchers.IO дээр дууд. Одоогийн багц 8 файл, 180 MB. Сүлжээ, түлхүүр хэрэггүй.

Багц дээрх маршрут, офлайн ​

kotlin
// In an app: File(packDir, "manifest.json").readText()
val manifest = PackRouteManifest.fromJson("""
{"id":"mongolia-260927-416081b1","bbox":[87.7845,41.03732,120.01834,52.25102],
 "request":{"costing":"auto","costing_options":{"auto":{"use_tracks":0.5}}},"confidence":"osm_only",
 "attribution":"© OpenStreetMap contributors (ODbL 1.0, openstreetmap.org/copyright). Track scores © dock.","note":"route cost is from track scores, not an ETA",
 "closures":{"method":"dock_steppe.closures v1","source":"partner reports","as_of":"2026-10-03","current":1,"ids_sha256":null,
  "buffer_m":15,"rule":"","active_when":"from <= route day, and route day <= to when to is set",
  "valhalla_limits":{"perimeter_m":10000,"vertices":100},
  "items":[{"id":"cl-000002","kind":"washout","from":"2026-10-04","to":null,"confidence":0.5,"perimeter_m":890,"vertices":5,
   "ring":[[104.499,47.499],[104.501,47.499],[104.501,47.501],[104.499,47.501],[104.499,47.499]]}]}}
""")
val r = packRoute(manifest, listOf(LonLat(106.9176, 47.9187), LonLat(102.833, 47.196)), "2026-10-04")
// In an app: POST r.body.toString() to /route on your own Valhalla, the pack tiles.tar as mjolnir.tile_extract
println("${r.closures.joinToString(" ")} ${r.body["costing"]}")
println(r.traceNote ?: "scored")
try {
    packRoute(manifest, listOf(LonLat(106.9176, 47.9187), LonLat(104.5, 47.5)), "2026-10-04")
} catch (e: EndInClosureException) {
    println("refused ${e.stop} ${e.closure}")
}

manifest нь багцын manifest.json. packRoute(manifest, stops, day, closures) нь багц дээр stops (2 ба түүнээс олон LonLat) цэгээр дайрах маршрутын хүсэлтийг бэлдэнэ. body (JsonObject)-г өөрийн Valhalla-ийн /route руу POST хий, багцын tiles.tar-ыг mjolnir.tile_extract болгоно. Түүнд manifest-ийн request (одоо costing auto, costing_options.auto.use_tracks 0.5), маршрутын өдөр (day, анхдагч нь Улаанбаатарын өнөөдөр) идэвхтэй хаалтуудын цагиргууд exclude_polygons болж, units km орно. Хаалтыг багцын closures хэсгээс, эсвэл илүү шинэ GET /v1/closures хариу болох closures-оос авна. Хариуны closures тойрсон хаалтуудыг нэрлэнэ: маршруттай хамт харуул. Багцын bbox-оос гадуурх цэг IllegalArgumentException шиднэ. Тойрох цагираг доторх цэг EndInClosureException (stop, closure) шиднэ: тэнд Valhalla-д зам алга; GET /v1/route-ийн адил маршрутаас татгалз. Valhalla-ийн цагирагийн хязгаараас хэтэрвэл ClosuresOverLimitException; хаалтын as_of-оос өмнөх өдөр IllegalArgumentException шиднэ, excludePolygons-ийн адил. Маршрут бүртэй attribution-г харуул. Багцад аяллын оноо байхгүй үед (confidence osm_only, одоогийн багц) scored нь false: жолоочид traceNoteMn (англиар traceNote)-г хэл. Багцын manifest-д confidence_note, confidence_note_mn хоёулаа байвал (offline v10-аас хойш) багцын өөрийн үг; үгүй бол SDK-ийн PACK_TRACE_NOTE. Хариултын confidenceNote (confidenceNoteMn) нь ямар ч багцад confidence-ийн утгыг хэлнэ: manifest-ийнх, үгүй бол оноогүй багцад SDK-ийнх, бусад үед null. Одоогийн багц дээр Улаанбаатараас Хархорин хүрэх хүсэлт pyvalhalla 3.9.0-д 359.8 км, багцын өөрийн шалгалттай ижил; тэр маршрутын дунд туршилтын хаалт тавихад ижил дуудлага түүнийг тойрч 690.3 км болно. Эхлээд багцын файлыг шалга (дээр). Сүлжээ, түлхүүр хэрэггүй.

Голын гарам, офлайн ​

kotlin
// In an app: File(packDir, "crossings.geojson").readText()
val crossings = PackCrossings.fromJson("""
{"type":"FeatureCollection","match_m":5,"note":"From OSM tags, not field checked.",
 "note_mn":"OSM-ийн шошгоос, газар дээр шалгаагүй.",
 "flow":{"attribution":"River flow: GEOGLOWS ECMWF Streamflow Service v2, CC BY 4.0"},
 "features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[101.95425,46.77663]},"properties":{
  "kind":"ford","waterway":"river","name":"Улаан гол","name_en":"Ulaan gol","intermittent":false,
  "flow":{"river_id":320103663,"normal_m3s":[0.59,0.42,0.63,0.88,1.17,1.37,2.19,2.3,1.57,1.14,0.94,0.8],
   "high_months":[7,8],"reach":"agrees","confidence":0.4}}}]}
""")
val line = listOf(LonLat(101.94, 46.775), LonLat(101.95425, 46.77663), LonLat(101.96, 46.78))
val r = crossingsOnRoute(crossings, line, 7)
for (w in r.warnings) println("${w.kind} ${w.name} ${w.highWater} ${w.monthM3s} ${w.alongM}")
println(r.flowAttribution ?: "")

Офлайн хээрийн багц ба өөрийн Valhalla дээрх аялалд. crossings нь багцын crossings.geojson (manifest-ийн files[1]); хэрэглэхийн өмнө sha256-ийг нь manifest-тэй тулга, хавтангийн адил. crossingsOnRoute(crossings, line, month) нь аяллын шугам matchM (5 м) дотор өнгөрөх гарам (kind ford) болон OSM-д гүүр, гарц тэмдэглээгүй огтлолцлыг (kind none) аяллын дарааллаар өгнө. alongM нь аяллын эхнээс хамгийн ойрын цэг хүртэлх метр, offM нь шугамаас холдох метр. Гол дээр month (1-12, анхдагч нь ubMonth(), Улаанбаатарын энэ сар) highMonths-д байвал highWater нь true, monthM3s нь тухайн сарын 1991-2020 оны дундаж урсац. doubtful гэж тэмдэглэсэн хэсэгт (загварын хэсэг голынхоосоо 10 дахин бага), мөн confidence 0.1 (LOW_FLOW_CONFIDENCE) буюу түүнээс бага хэсэгт monthM3s нь null: тоог биш, сарыг харуул. Шалтгааныг snap хэлнэ: none_fits бол тэнд голыг дагасан загварын хэсэг алга; main_stem бол суваг зөвхөн жижиг хэсгийг дагадаг тул голын гол урсгалыг авсан. Хээрийн самбар ч ингэдэг. Горхи, сувагт урсац байхгүй: highWater нь null. Гол нууранд цутгахдаа салаалдаг, салаа бүр хэдий хэр ус авдгийг загварын аль ч хэсэг хэлэхгүй бэлчирийн салаан дээр урсац null, delta нь lake, lakeOsm, river-ийг өгнө: "бэлчирийн салаа, урсац тодорхойгүй" гэж харуул. Бусад газар болон дүрмээс өмнөх багцад delta нь null. lake нэг бичигт оруулсан бол lakeNameOsm нь нуурын OSM бичвэр, эс бөгөөс null; lake-ийг харуул. national crossings v11-ээс өмнөх багцад байхгүй: null. Хоёр үзүүр нь нэг нэртэй гол дээр байгаа нэргүй гол, горхи бол тэр голын салаа: channelOf нь name, nameEn, riverWayId-г өгнө, "Улаан гол, нэргүй салаа" гэж харуул. OSM-ийн зургаас, газар дээр шалгаагүй. Бусад газар болон дүрмээс өмнөх багцад channelOf нь null. Ус нь урсгалаараа (OSM шугамыг урсгалын чигээр зурдаг) нэг нэртэй голд хүрдэг бусад нэргүй гол, горхи flowsInto-тай: name, nameEn, riverWayId, ways нь тэр гол хүртэлх нэргүй шугамын хамгийн цөөн тоо. "Орхон гол, нэргүй цутгал" гэж харуул. OSM-ийн зургаас, газар дээр шалгаагүй; эсрэг чигээр зурсан шугам буруу гол өгөх эсвэл юу ч өгөхгүй. Хоёулаа байвал channelOf давамгайлна. Бусад газар болон дүрмээс өмнөх багцад flowsInto нь null. road нь аяллын замын OSM-ийн highway, surface шошго, paved-ийг өгнө: аль нэг нь хатуу хучилттай бол true, бүгд хучилтгүй бол false, surface шошгогүй зам байвал null. Зөвхөн шинэ зам дээр болон дүрмээс өмнөх багцад road нь null. Хатуу хучилттай зам дээрх none гарц нь OSM-д тэмдэглээгүй гүүр, хоолой байж болно; "хатуу хучилттай зам, OSM-д гүүр тэмдэглээгүй" гэж харуул. Багцын onPaved хатуу хучилттай гарцыг тоолно, roadRule, roadRuleMn дүрмийг өгнө. Багцын nearBridge нь усны хажууд зурсан гүүрээр гатлах тул багцад ороогүй none гарцыг тоолно, bridgeRule, bridgeRuleMn дүрмийг өгнө. Багцын onePoint нь усны шугам зам дээр хоёр хэсэг болж тасарсан тул хажуу гарцтайгаа нэг болсон гарцыг тоолно, splitRule, splitRuleMn дүрмийг өгнө. Багцын fromSeasonal нь OSM-ийн intermittent шошгогүй, зөвхөн seasonal шошгоор түр урсгалтай гэж тэмдэглэсэн гарцыг тоолно, intermittentRule, intermittentRuleMn дүрмийг өгнө. fordNodeId-тай гарам нь зөвхөн OSM-ийн гарамын зангилаанаас: тэнд OSM-д усны шугам зураагүй тул waterway нь unknown, нэр, урсацгүй; "OSM-ийн гарам, ус зураагүй" гэж харуул. Бусад гарц болон дүрмээс өмнөх багцад fordNodeId нь null. Багцын fordNodes тэднийг тоолно, fordNodeRule, fordNodeRuleMn дүрмийг өгнө. Анхааруулгатай хамт noteMn-ийг харуул: OSM-ийн шошгоос, газар дээр шалгаагүй. flowAttribution null биш бол харуул. 2-оос цөөн цэгтэй шугам эсвэл буруу сар IllegalArgumentException шиднэ. Сүлжээ, түлхүүр шаардахгүй. JS SDK-тэй ижил дүрэм, ижил туршилтын тохиолдол.

Шатахуун, гэр бааз, офлайн ​

kotlin
// In an app: File(packDir, "pois.geojson").readText()
val pois = PackPois.fromJson("""
{"type":"FeatureCollection","registry_checked":true,
 "counts":{"fuel":{"registered":1,"unregistered":1268},"ger_camp":{"registered":0,"unregistered":175}},
 "written":1,"rule":"every registered fuel station and ger camp, all Mongolia","rule_mn":"бүртгэлтэй бүх ШТС, гэр бааз",
 "source":"OpenStreetMap","note":"From OSM, not field checked. Unregistered places are counted, not shown.",
 "note_mn":"OSM-ээс, газар дээр шалгаагүй. Бүртгэлгүй газрыг тоолсон, харуулаагүй.",
 "features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[101.9601,46.7801]},"properties":{
  "kind":"fuel","osm":"N1","name":"Жишээ ШТС","name_en":"Example fuel station","reg_number":"0000000"}}]}
""")
val route = listOf(LonLat(101.94, 46.775), LonLat(101.95425, 46.77663), LonLat(101.96, 46.78))
val near = poisOnRoute(pois, route)
for (p in near.pois) println("${p.kind} ${p.name} ${p.regNumber} ${p.alongM} ${p.offM}")
println("${near.registryChecked} ${near.unlistedFuel} ${near.unlistedGerCamp}")

pois нь багцын pois.geojson (manifest files[2], index.json-д pois_sha256); хэрэглэхийн өмнө sha256-ийг нь manifest-тэй тулга, хавтангийн адил. poisOnRoute(pois, line, nearM) нь аяллын шугамаас nearM дотор орших шатахуун түгээх станц (kind fuel), гэр баазыг (kind ger_camp) аяллын дарааллаар өгнө. Анхдагч нь 2000 м (POI_NEAR_M), хээрийн маршрутын хуудастай адил. alongM нь аяллын эхнээс хамгийн ойр цэг хүртэлх метр, offM нь шугамаас холдох метр, хоёулаа бүхэл метр. Файлд зөвхөн улсын бүртгэлтэй тулгасан газар бүртгэлийн нэр, regNumber-тайгаа орно. Бусдыг Монгол даяар төрлөөр нь тоолсон, нэр, байршилгүй: unlistedFuel, unlistedGerCamp. unlistedFuel 0-ээс их байхад хоосон жагсаалт нь "энэ замд шатахуун байхгүй" гэсэн үг биш. registryChecked нь false бол багц хийх үед бүртгэлийг уншиж чадаагүй: "байхгүй" биш, "шалгаагүй" гэж хэл. Газруудтай хамт noteMn-ийг харуул. 2026-10-03-аас өмнөх багцад pois.geojson байхгүй. Одоогийн багцад 0 газар: 1,268 шатахуун түгээх станц, 175 гэр баазыг тоолсон, бүртгэлтэй тулгасан нь хараахан алга. 2-оос цөөн цэгтэй шугам эсвэл 0-ээс ихгүй nearM IllegalArgumentException шиднэ. Сүлжээ, түлхүүр шаардахгүй.

Намгархаг газар, офлайн ​

kotlin
// In an app: File(packDir, "wetlands.geojson").readText()
val wetlands = PackWetlands.fromJson("""
{"type":"FeatureCollection","written":1,"km":0.4,"areas":1,"counts":{"marsh":{"stretches":1,"km":0.4}},
 "match_m":5,"rule":"the part of one OSM car way inside an OSM natural=wetland area",
 "rule_mn":"OSM-ийн natural=wetland талбай доторх нэг машин замын хэсэг","source":"OpenStreetMap",
 "note":"From OSM tags, not field checked. Soft ground in spring and after rain.",
 "note_mn":"OSM-ийн шошгоос, газар дээр шалгаагүй. Хавар, бороо орсны дараа зөөлөн газар.",
 "features":[{"type":"Feature","geometry":{"type":"LineString","coordinates":[[101.94285,46.775326],[101.94855,46.775978]]},
  "properties":{"wetland":"marsh","area":"way/1","name":null,"km":0.441,"way_id":2,"new_track":false,
  "road":{"highway":["track"],"surface":["ground"],"paved":false}}}]}
""")
val route = listOf(LonLat(101.94, 46.775), LonLat(101.95425, 46.77663), LonLat(101.96, 46.78))
val wet = wetlandsOnRoute(wetlands, route)
for (s in wet.stretches) println("${s.wetland} ${s.alongM} ${s.onM} ${s.km}")
println("wet ${wet.onM}")

wetlands нь багцын wetlands.geojson (manifest-ийн files мөр ба wetlands хэсэг, index.json-д wetlands_sha256); хэрэглэхийн өмнө sha256-ийг нь manifest-тэй тулга, хавтангийн адил. Хэсэг бүр нь OSM-ийн natural=wetland талбай доторх нэг машин замын хэсэг, талбайн хилээр тасалсан: хавар, бороо орсны дараа зөөлөн газар. wetlandsOnRoute(wetlands, line) нь аяллын явах хэсгүүдийг аяллын дарааллаар өгнө. Хэсгийг matchM (5 м)-ээс ихгүй жижиг хэсгүүдэд хуваана; жижиг хэсгийн хоёр үзүүр шугамаас matchM дотор байвал аялал түүгээр явна. Ийм хэсгүүд нийлээд 20 м (WETLAND_MIN_ON_M) буюу түүнээс их, эсвэл хэсэг бүхэлдээ бол аялал тэр хэсгээр явна: зөвхөн хөндлөн гарах аялал түүгээр явахгүй. alongM нь аяллын эхнээс хэсэгтэй нийлэх цэг хүртэлх метр, onM нь аяллын явах метр, хоёулаа бүхэл метр; km нь багц дахь хэсгийн бүтэн урт. wetland нь OSM-ийн төрөл (marsh, bog, wet_meadow, fen, ...), талбай wetland шошгогүй бол unknown; area нь OSM талбай, жишээ нь relation/8128712. Зөвхөн шинэ зам дээр wayId, road нь null. "OSM-ийн намаг 1.2 км, хавар зөөлөн" гэж харуул. Хэсгүүдтэй хамт noteMn-ийг харуул: OSM-ийн шошгоос, газар дээр шалгаагүй; хуучин намаг одоо хуурай байж болно, OSM-д зураагүй намаг энд байхгүй. Хоосон жагсаалт нь "зам бүхэлдээ хуурай" гэсэн үг биш. Одоогийн багцад 356 хэсэг, 86 OSM талбайд 247.3 км, үүний 208.4 км нь намаг. 2026-10-03-аас өмнөх багцад wetlands.geojson байхгүй. 2-оос цөөн цэгтэй шугам IllegalArgumentException шиднэ. Сүлжээ, түлхүүр шаардахгүй.

Уулын даваа, офлайн ​

kotlin
// In an app: File(packDir, "passes.geojson").readText()
val passes = PackPasses.fromJson("""
{"type":"FeatureCollection","written":1,"counts":{"mountain_pass":1},"named":1,"with_ele":1,"with_dem":1,"match_m":5,
 "rule":"an OSM node tagged mountain_pass=yes or natural=saddle that is a node of a car way",
 "rule_mn":"машин замын зангилаа болох, mountain_pass=yes эсвэл natural=saddle шошготой OSM зангилаа","source":"OpenStreetMap",
 "note":"From OSM tags, not field checked. A climb, and snow and ice outside summer.",
 "note_mn":"OSM-ийн шошгоос, газар дээр шалгаагүй. Өгсүүр зам, зуны бус улиралд цас мөс.",
 "features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[101.957125,46.778315]},
  "properties":{"kind":"mountain_pass","name":"Улаан даваа","name_en":null,"ele_m":2391,"ele_osm":"2391","node_id":3,"dem_m":2388,
  "route_way_ids":[2],"new_track":false,"road":{"highway":["track"],"surface":["ground"],"paved":false}}}],
 "dem":{"source":"copernicus-dem-glo30","attribution":"Copernicus DEM GLO-30","tiles":1,"missing":[],
  "rule":"the height of the GLO-30 cell the node falls in","rule_mn":"зангилаа байрлах GLO-30 нүдний өндөр",
  "note":"A surface model, not field checked.","note_mn":"Гадаргын загвар, газар дээр шалгаагүй."}}
""")
val route = listOf(LonLat(101.94, 46.775), LonLat(101.95425, 46.77663), LonLat(101.96, 46.78))
val over = passesOnRoute(passes, route)
for (p in over.passes) {
    val height = p.eleM?.let { "${it.toInt()} m" } ?: "no height in OSM"
    println("${p.name ?: p.kind} ${p.alongM} ${p.offM} $height")
}
println("top ${over.topM?.toInt() ?: "none"}")
println("top DEM ${over.topDemM?.toInt() ?: "none"} ${over.dem?.attribution ?: ""}")

passes нь багцын passes.geojson (manifest-ийн files мөр ба passes хэсэг, index.json-д passes_sha256); хэрэглэхийн өмнө sha256-ийг нь manifest-тэй тулга, хавтангийн адил. Даваа бүр нь машин замын зангилаа болох, mountain_pass=yes эсвэл natural=saddle шошготой OSM зангилаа: өгсүүр зам, зуны бус улиралд цас мөс. passesOnRoute(passes, line) нь аяллын гарах даваануудыг аяллын дарааллаар өгнө: зангилаа нь шугамаас matchM (5 м) дотор байгаа даваа, хээрийн маршрутын хуудасны дүрэм. alongM нь аяллын эхнээс даваанд хамгийн ойр цэг хүртэлх бүхэл метр; offM нь шугамаас хэдэн метр, 0.1 м-ээр. kind нь mountain_pass, OSM-д зөвхөн natural=saddle байвал saddle. eleM нь OSM-ийн ele шошгыг метрээр уншсан утга, шошгогүй эсвэл өөр бичвэртэй ("7000 ft" гэх мэт) бол null; eleOsm нь шошго бичсэнээрээ. topM нь аялал дээрх даваануудын хамгийн их eleM, аль нь ч өндөргүй бол null: тэгш гэсэн үг биш, OSM-д тоо алга. demM нь хоёр дахь өндөр, Copernicus GLO-30 DEM-ээс: зангилаа байрлах 30 м нүдний өндөр, бүхэл метрээр; багцад тэнд байхгүй бол null. eleM-тэй хэзээ ч хольдоггүй. topDemM нь аялал дээрх хамгийн их demM, аль нь ч байхгүй бол null. "120 дахь км-т даваа, 2,391 м (OSM)", OSM-д тоо байхгүй бол "ойролцоогоор 1,911 м (DEM)" гэж харуул; DEM өндөр харуулах газар бүрт dem.attribution-ийг харуул. passes v1 багцад dem нь null, demM бүр null. Зөвхөн шинэ зам дээр road нь null. Даваануудтай хамт noteMn-ийг харуул: OSM-ийн шошгоос, газар дээр шалгаагүй; OSM-д зураагүй даваа энд байхгүй. Хоосон жагсаалт нь "зам бүхэлдээ тэгш" гэсэн үг биш. Одоогийн багцад машин зам дээр 74 даваа (68 mountain_pass, 6 saddle), 41 нь нэртэй, 40 нь OSM өндөртэй, 1,210-3,104 м, 74 нь DEM өндөртэй, 1,214-3,202 м. 2026-10-03-аас өмнөх багцад passes.geojson байхгүй. 2-оос цөөн цэгтэй шугам IllegalArgumentException шиднэ. Сүлжээ, түлхүүр шаардахгүй.

heightsDiffer нь багцын тэмдэг: eleM, demM хоёулаа байгаа бөгөөд dem.differM (50 м)-ээс илүү зөрвөл true, дотор нь бол false, аль нэг нь байхгүй бол null. true нь хоёрын нэг нь буруу гэсэн үг, алийг нь хэлэхгүй: хоёр өндрийг хоёуланг нь, "2,241 м (OSM); ойролцоогоор 2,349 м (DEM)", dem.differRuleMn-тэй хамт харуул. differ нь аялал дээрх true даваануудын тоо, багцад тэмдэг байхгүй бол null: шалгаагүй, 0 биш. passes v2 багцад тэмдэг байхгүй. Одоогийн багцад 74-өөс 1 нь true, 39 нь false, 34 нь null.

Элс, офлайн ​

kotlin
// In an app: File(packDir, "sand.geojson").readText()
val sand = PackSand.fromJson("""
{"type":"FeatureCollection","written":1,"km":0.346,"areas":1,"named":1,"on_paved":0,"match_m":5,
 "rule":"the part of one OSM car way inside an OSM natural=sand area; an area also tagged golf is left out",
 "rule_mn":"OSM-ийн natural=sand талбай доторх нэг машин замын хэсэг; golf шошготой талбайг тооцохгүй","source":"OpenStreetMap",
 "note":"From OSM tags, not field checked. A car can dig in and stop.",
 "note_mn":"OSM-ийн шошгоос, газар дээр шалгаагүй. Машин суух аюултай.",
 "features":[{"type":"Feature","geometry":{"type":"LineString","coordinates":[[101.9554,46.777304],[101.95885,46.779326]]},
  "properties":{"area":"way/1","name":"Бага элс","km":0.346,"way_id":2,"new_track":false,
  "road":{"highway":["track"],"surface":["sand"],"paved":false}}}]}
""")
val route = listOf(LonLat(101.94, 46.775), LonLat(101.95425, 46.77663), LonLat(101.96, 46.78))
val onSand = sandOnRoute(sand, route)
for (s in onSand.stretches) println("${s.name ?: s.area} ${s.alongM} ${s.onM} ${s.km}")
println("sand ${onSand.onM}")

sand нь багцын sand.geojson (manifest-ийн files мөр ба sand хэсэг, index.json-д sand_sha256); хэрэглэхийн өмнө sha256-ийг нь manifest-тэй тулга, хавтангийн адил. Хэсэг бүр нь OSM-ийн natural=sand талбай доторх нэг машин замын хэсэг, талбайн хилээр тасалсан; golf шошготой талбай нь гольфын элсэн нүх тул тооцохгүй. Машин суух аюултай. sandOnRoute(sand, line) нь аяллын явах хэсгүүдийг аяллын дарааллаар өгнө, wetlandsOnRoute-ийн дүрмээр: хэсгийг matchM (5 м)-ээс ихгүй жижиг хэсгүүдэд хуваана; жижиг хэсгийн хоёр үзүүр шугамаас matchM дотор байвал аялал түүгээр явна. Ийм хэсгүүд нийлээд 20 м (SAND_MIN_ON_M) буюу түүнээс их, эсвэл хэсэг бүхэлдээ бол аялал тэр хэсгээр явна: зөвхөн хөндлөн гарах аялал түүгээр явахгүй. alongM нь аяллын эхнээс хэсэгтэй нийлэх цэг хүртэлх метр, onM нь аяллын явах метр, хоёулаа бүхэл метр; km нь багц дахь хэсгийн бүтэн урт. area нь OSM талбай, жишээ нь relation/5149547, name нь түүний OSM нэр эсвэл null. Зөвхөн шинэ зам дээр wayId, road нь null. Зарим хотын гудамж элсэн талбай дотор зурагдсан: 25 хэсэг хатуу хучилттай зам дээр, үүний 24 нь Замын-Үүдэд; road?.paved тэдгээрийг ялгана. "40 дэх км-т элс, 1.2 км" гэж харуул. Хэсгүүдтэй хамт noteMn-ийг харуул: OSM-ийн шошгоос, газар дээр шалгаагүй; манхан нүүдэг, OSM-д зураагүй элс энд байхгүй. Хоосон жагсаалт нь "замд элс байхгүй" гэсэн үг биш. Одоогийн багцад 686 хэсэг, 66 OSM талбайд 669.6 км, үүний 153 хэсэг нь нэртэй талбайд; хамгийн их нь Бор хар элс, 70.3 км. 2026-10-03-аас өмнөх багцад sand.geojson байхгүй. 2-оос цөөн цэгтэй шугам IllegalArgumentException шиднэ. Сүлжээ, түлхүүр шаардахгүй.

Усны цэг, офлайн ​

kotlin
// In an app: File(packDir, "water.geojson").readText()
val water = PackWater.fromJson("""
{"type":"FeatureCollection","written":1,"counts":{"water_well":1},"named":1,"drinkable":{"yes":0,"no":0,"unknown":1},"near_m":2000,
 "rule":"an OSM node or way tagged amenity=drinking_water or water_point, man_made=water_well or water_tap, or natural=spring",
 "rule_mn":"amenity=drinking_water эсвэл water_point, man_made=water_well эсвэл water_tap, эсвэл natural=spring шошготой OSM зангилаа эсвэл зам",
 "near_rule":"within 2000 m of the route line","near_rule_mn":"маршрутын шугамаас 2000 м дотор","source":"OpenStreetMap",
 "note":"From OSM tags, not field checked. A well may be dry, broken or locked.",
 "note_mn":"OSM-ийн шошгоос, газар дээр шалгаагүй. Худаг ширгэсэн, эвдэрсэн эсвэл цоожтой байж болно.",
 "features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[101.951,46.7805]},
  "properties":{"kind":"water_well","name":"Хар худаг","name_en":null,"drinkable":null,"drinking_water":null,"pump":null,"osm":"node/4"}}]}
""")
val route = listOf(LonLat(101.94, 46.775), LonLat(101.95425, 46.77663), LonLat(101.96, 46.78))
val near = waterOnRoute(water, route)
for (w in near.water) {
    val drink = w.drinkable?.let { if (it) "drinkable" else "not drinkable" } ?: "not known"
    println("${w.name ?: w.kind} ${w.alongM} ${w.offM} $drink")
}
println("drinkable ${near.drinkable.yes} of ${near.water.size}")

water нь багцын water.geojson (manifest-ийн files мөр ба water хэсэг, index.json-д water_sha256); хэрэглэхийн өмнө sha256-ийг нь manifest-тэй тулга, хавтангийн адил. Цэг бүр нь amenity=drinking_water эсвэл water_point, man_made=water_well эсвэл water_tap, эсвэл natural=spring шошготой OSM зангилаа эсвэл зам; замыг гадаргуу дээрх нэг цэгээр авна. waterOnRoute(water, line) нь аяллын шугамаас nearM дотор байгаа цэгүүдийг аяллын дарааллаар өгнө, шатахуун түгээх газар, жуулчны баазын адил: өөрөө өгөхгүй бол багцын nearM (2000 м). alongM нь аяллын эхнээс усанд хамгийн ойр цэг хүртэлх метр, offM нь шугамаас хэдэн метр, хоёулаа бүхэл метр. kind нь drinking_water, water_point, water_tap, water_well, spring дарааллаар эхэлж таарсан нь. drinkable нь зөвхөн OSM-ийн бичсэн зүйл: drinking_water=yes эсвэл тэр шошгогүй ундны усны цэг бол true, drinking_water=no бол false, OSM юу ч бичээгүй бол null; төрлөөс нь таамаглахгүй, тиймээс null нь "мэдэгдэхгүй", "уух боломжгүй" гэсэн үг биш. drinkingWater, pump нь OSM шошго бичсэнээрээ. Хариуны drinkable нь олдсон цэгүүдийн дундах yes, no, unknown тоо. "40 дэх км-ээс 1.2 км-т худаг" гэж харуул. Цэгүүдтэй хамт noteMn-ийг харуул: OSM-ийн шошгоос, газар дээр шалгаагүй; худаг ширгэсэн, эвдэрсэн эсвэл цоожтой байж болно, OSM-д зураагүй усны цэг энд байхгүй. Хоосон жагсаалт нь "замд ус байхгүй" гэсэн үг биш. Одоогийн багцад 1,064 цэг (691 худаг, 211 булаг, 68 ундны ус, 48 усны цэг, 46 цорго), 200 нь нэртэй; OSM 97-д нь ундны, 5-д нь ундны биш гэж бичсэн, 962-т юу ч бичээгүй; 205 нь 46 N-ээс урагш. 2026-10-03-аас өмнөх багцад water.geojson байхгүй. 2-оос цөөн цэгтэй шугам эсвэл 0-ээс ихгүй nearM IllegalArgumentException шиднэ. Сүлжээ, түлхүүр шаардахгүй.

wetlands.geojson, passes.geojson, sand.geojson, water.geojson, crossings.geojson дахь нэр: OSM заримдаа кирилл үгийн дотор латин үсэг бичдэг, жишээ нь латин o-той "Хонгoрын Элс". Бусад үсэг бүр ижил харагдах ихэртэй бол багц ийм үгийг нэг бичигт оруулна. name нь засагдсан нэр, nameOsm нь OSM-ийн бичвэр, name нь OSM-ийн бичвэр бол null. name-ийг харуул. Хариу бүр nameOsm, багцын дүрэм nameRule, nameRuleMn-ийг агуулна, багцад дүрэм байхгүй бол null. Одоогийн багцад элсний 686 хэсгээс 17 нь засагдсан, бүгд "Хонгорын Элс"; намаг, даваа, ус, гарцад 0. offline v11 (элс), v12 (намаг, даваа, ус), v13 (гарц)-аас өмнөх багцад аль аль нь байхгүй: null.

Суурь зураг, офлайн ​

kotlin
// In an app: File(packDir, "manifest.json").readText()
val basemap = PackBasemap.fromManifest("""
{"basemap":{"method":"dock_steppe.basemap v1","file":"basemap.pmtiles","format":"pmtiles","schema":"openmaptiles",
 "schema_version":"3.16.0","tile_type":"mvt","tiles":305104,"minzoom":0,"maxzoom":14,
 "bounds":[87.70255,41.50035,120.02014,52.19582],"layers":["boundary","building","landcover","landuse","park","place",
 "transportation","transportation_name","water","water_name","waterway"],"excluded_layers":["poi","housenumber"],
 "languages":["mn","en"],"osm_time":"2026-09-27T20:23:36Z",
 "attribution":"© OpenMapTiles (openmaptiles.org) © OpenStreetMap contributors","rule":"no poi, no housenumber",
 "rule_mn":"poi, housenumber давхаргагүй"}}
""")
val style = basemapStyle(basemap, "file:///data/user/0/com.example/files/pack/basemap.pmtiles", BasemapStyleOptions(lang = "mn"))
println("${basemap?.tiles} ${style.keys}")

PackBasemap.fromManifest(text) нь багцын manifest.json-ийн basemap хэсгийг уншина, байхгүй бол null (2026-10-03-аас өмнөх багц). basemap.pmtiles түүний хажууд байна (manifest files[3], index.json-д basemap_sha256; хавтангийн адил sha256-ийг нь тулга). basemapStyle(basemap, url, options) түүнд зориулсан MapLibre-ийн бүтэн загвар өгнө, JS SDK-ийн basemapStyle-тэй ижил JSON: газрын бүрхэвч, ус, гол, хээрийн шороон зам (бор, тасархай; файлд 14-р томруулалтаас эхэлж бий), зам, төмөр зам, улс, аймгийн хил, барилга. MapLibre Native-д Style.Builder().fromJson(style.toString()) гэж өг; MapLibre Native эх сурвалжийн pmtiles:// URL-ийг өөрөө уншина. file:// URL өг: MapLibre Native 13.6.1 asset://-аас юу ч зурахгүй, тиймээс APK-д орсон багцыг эхлээд апп-ын файл руу хуул. Эх сурвалж нь хэсгийн attribution-ийг авч явна, тиймээс газрын зураг "© OpenStreetMap contributors" гэж харуулна; харуулсаар байлга. Багцад фонт байхгүй, тиймээс нэр харуулахад glyphs (өөрийн фонтын URL, {fontstack}, {range}), fonts (анхдагч Noto Sans Regular) хэрэгтэй; тэгвэл газар, ус, замын нэрийг lang-аар ("mn" анхдагч, эсвэл "en") бичнэ, байхгүй бол OSM-ийн нэрээр. Файлд аж ахуйн газрын нэр, байрны дугаар байхгүй: дэлгүүрийн нэрийг зөвхөн бүртгэлтэй бол харуулна (poisOnRoute), хаяг нь төрийн албан ёсны хаяг. Хэсэг байхгүй, poi эсвэл housenumber давхаргатай эсвэл OpenMapTiles вектор PMTiles биш хэсэг, хэсэгт байхгүй lang, хоосон url IllegalArgumentException шиднэ. Одоогийн багц: 112.6 MB, 305,104 хавтан, 0-14 томруулалт, 2026-09-27-ны OSM. Сүлжээ, түлхүүр шаардахгүй. Хувилбар бүр жижиг PMTiles файлаас file://-ээр эмулятор дээр зурж, ус, газрын өнгийг шалгадаг.

Буруу хаалга мэдэгдэх ​

kotlin
val receipt = dock.reportDoor(DoorReport.WrongLocation("7QSVX", LonLat(106.9303, 47.9202)))
println("${receipt.status} ${receipt.next}")

Мөн DoorReport.Missing, DoorReport.Duplicate, DoorReport.Unmapped. Мэдэгдэл бүрийг хүн хянана; түүнээс өмнө хаалганы мэдээлэл өөрчлөгдөхгүй. note дотор нэр, утасны дугаар бичихгүй.

Газрыг id-гаар дахин авах ​

kotlin
val first = dock.geocode("Сансар").results[0]
val p = dock.place(first.id)
val inside = if (p.parents == null) "эцэг байхгүй" else "барилга дотор"
println("${p.kind} $inside")

Id нь geocode, reverse, changes-ийн өгсөн. parents нь хаалганы харьяалах газруудын id; бусад төрөлд null. Хуучирсан id нь DockError 410 retired, дахин ашиглагдахгүй. geocode:read.

Тухайн цагаас хойшхи өөрчлөлт ​

kotlin
import java.util.Date

val copy = HashMap<String, Address>()
var page = dock.changes(Date(0), limit = 1000)
while (true) {
    for (c in page.changes) {
        if (c.state == "current") copy[c.id] = dock.place(c.id) else copy.remove(c.id)
    }
    val next = page.next ?: break
    page = dock.changes(null, limit = 1000, cursor = next)
}
println("${copy.size} хүртэл ${page.until}")

Хуулбарыг шинэчилж байлгана. Нэг дуудлагад нэг хуудас, хуучнаас нь эхэлнэ; дараа нь since = page.until-ээр дахин асууна. Cursor-тай үед since нь null. limit-ийг дуудлага бүрд өгнө (анхдагч 100). current: place()-ээр авна. retired, hidden: хасна. Түншийн түлхүүр (changes:read).

Жолоочийн баталгаа ​

kotlin
val r = dock.confirm(Confirmation(
    Confirmation.Target.Code("7QSVX"), Confirmation.Result.Confirmed(LonLat(106.93012, 47.92011)),
    device = LonLat(106.9302, 47.9203), driver = "drv-7f3a"))
println("${r.status} ${r.next}")

Үр дүн нь Confirmed(tap), WrongLocation(tap) эсвэл Missing. Хаалгыг Target.Code-оор, код байхгүй бол Target.Entrance(id)-аар (хаалганы tile давхаргын id). tap нь жолоочийн газрын зураг дээр дарсан хаалганы цэг; device нь газар дээрх утасны GPS, зөвхөн шалгалт, дарсан цэгээс 40 м дотор. driver нь жолоочийн таны өөрийн id, зөвхөн hash хэлбэрээр хадгалагдана: утасны дугаар, и-мэйл, нэр хэзээ ч биш. observedAt нь офлайн хүлээгдсэн баталгаанд, 7 хоногоос хуучин биш. Түншийн түлхүүр (confirm:write).

Сарын баталгаа ​

kotlin
val own = dock.ownConfirmations("2026-10")
println("${own.month} ${own.closed} ${own.totals.confirmed} ${own.drivers} ${own.flagged.size}")

ownConfirmations нь жолоочийн баталгааны таны самбар: танай байгууллагын баталгаажуулалт ба хаалганы мэдэгдлийг сараар (YYYY-MM, Улаанбаатар) өгнө, өөр байгууллагын юуг ч уншихгүй. totals ба days-ийн өдөр бүр үр дүнгээр тоолно: confirmed, wrongLocation, missing, хаалганы мэдэгдлээс duplicate, unmapped. Мөр бүр жолооч газар дээр байсан Улаанбаатарын өдөрт тоологдоно (observedAt, эс бөгөөс хүлээн авсан цаг). drivers нь таны driver id-аар өөр өөр жолоочийн тоо, id-г өөрийг нь хэзээ ч өгөхгүй. flagged нь алдаатай цэгүүд: таны жолооч буруу байрлалтай, байхгүй эсвэл давхардсан гэсэн 100 хүртэл хаалга, олноос нь; хаалгыг нэрлэсэн бол code нь null. Хязгаарлалттай газрын хаалга хэзээ ч гарахгүй. Одоогийн сарыг ч өгнө; сар дууссанаас хойш 8 хоногийн дараа, дараалсан баталгаа нэмэгдэх боломжгүй болоход closed нь true. confirm:read хэрэгтэй, самбарын түлхүүрт зориулсан зөвхөн унших эрх: confirm:write үүнийг уншихгүй, confirm:read баталгаажуулж чадахгүй. Буруу сар бол 400 bad_month.

Хаалганы нэр ​

kotlin
val mine = dock.registerDoorName("Сансар бэйкери", "7QSVX")
val named = dock.doorByName("сансар-бэйкери")
println("${mine.status} ${mine.expiresAt} ${named.door.code} ${label(named.door, Lang.MN)}")

Бизнес хаалгандаа нэг удаа нэр өгнө, түлхүүртэй хэн ч тэр нэрээр хаалгыг олно (API 0.52.0). Бүх дуудлагад door_names боломж хэрэгтэй: dock таны байгууллагад нээх хүртэл 403 feature_off хариулна (usage-ийн features-ийг үзнэ үү). registerDoorName(name, code) names:write эрх шаардана. Нэрийг нэг жил хадгална, одоогоор төлбөргүй. Өөрийн нэрийг өөр кодтой илгээвэл тэр хаалга руу шилжинэ (status нь moved). 409 name_taken, 410 retired_code, 50 нэрээс хэтэрвэл 422 too_many. doorByName(name) door:read эрхээр хаалгыг door шиг, албан хаягийг эхэнд нь хариулна. Том жижиг үсэг, зай, цэг таслал, кирилл үсэгтэй адилхан латин үсгээр бичсэн ч олно. Олдоогүй нэр хаалганы алдааны хязгаарт тоологдоно. doorNames() таны нэрсийг A-Z дарааллаар жагсаана. Нэрийг өөр байгууллагад шилжүүлэх (API 0.53.0): doorNameTransferCode(name) dnt_ код өгнө, нэг л удаа харагдана, 7 хоног хүчинтэй. Нөгөө байгууллага claimDoorName(name, transferCode) дуудна; хаалга, дуусах хугацаа хэвээр. cancelDoorNameTransfer(name) кодыг цуцална. Үсэггүй, утасны дугаар эсвэл и-мэйлтэй нэрийг хүсэлт илгээхгүйгээр API-ийн 400-аар татгалзана: нэр URL-д ордог.

Хаалганы тэмдэглэл ​

kotlin
val sent = dock.writeDoorNotes(
    "Сансар бэйкери", instructionsMn = "Зүүн талын хаалга", instructionsEn = "East side, 2nd entrance",
)
val mine = dock.doorNotes("Сансар бэйкери")
val state = mine.notes.firstOrNull()?.state ?: "none"
println("${sent.status} $state")

Хаалганы нэр эзэмшдэг зочид буудал, байр, ресторан зочид хаалгаа хэрхэн олохыг writeDoorNotes(name, instructionsMn, instructionsEn)-ээр бичнэ (API 0.58.0): instructions_mn, instructions_en эсвэл хоёулаа, тус бүр 500 хүртэл тэмдэгт. names:write эрх, hotel.notes боломж хэрэгтэй, эс бөгөөс 403 feature_off. Тэмдэглэлийг хүн хянана; түүнээс өмнө door газрын зурагт байгаа тэмдэглэлийг өгсөөр байна. status нь queued, дахин бичвэл updated эсвэл unchanged. Тэмдэглэлд утасны дугаар эсвэл и-мэйл байвал 400 personal_data. doorNotes(name) (API 0.59.0) тэр хаалганд бичсэн өөрийн тэмдэглэлүүдийг waiting, accepted эсвэл refused, reviewed_at-тай жагсаана; өөр байгууллагынхыг хэзээ ч үгүй. Танай эзэмшдэггүй нэр 404 not_found. Нэрийг хаалганы нэртэй адил шалгаж, хүсэлт илгээхээс өмнө татгалзана.

Хаалганы зураг ​

kotlin
import java.io.File

// In an app: the file the camera wrote, in context.cacheDir
val gate = File(System.getProperty("java.io.tmpdir"), "gate.jpg")
val sent = dock.sendDoorPhoto("Сансар бэйкери", gate.readBytes())
val shown = dock.doorPhoto("Сансар бэйкери")
// Later: pass the sha256 you hold; an unchanged photo comes back with jpeg null
val again = dock.doorPhoto("Сансар бэйкери", sha256 = shown.sha256)
val size = shown.jpeg?.size ?: 0
println("${sent.status} $size ${again.jpeg == null}")

Хаалганы нэр эзэмшдэг байр, зочид буудал хаалгынхаа зургийг sendDoorPhoto(name, jpeg)-ээр илгээнэ (API 0.60.0): зочин ирэхдээ харах хаалга. Нэг JPEG файл, 2 MB хүртэл, тал бүр 320-8000 px, камерын хадгалснаар нь. Хадгалахаас өмнө мета өгөгдлийг нь хасна: GPS, утас, цаг. Эргүүлэлт хэвээр. Зургийг хүн хянана; нүүр, машины дугаар эсвэл утасны дугаар харагдвал татгалзана. status нь queued, дахин илгээвэл updated эсвэл unchanged. sha256 нь хадгалсан зургийнх, таны илгээсэн файлынх биш. JPEG биш бол 400 not_jpeg; invalid_photo, photo_too_small, photo_too_big; 2 MB-аас их бол 413 too_large. doorPhoto(name) (API 0.61.0) хүний зөвшөөрсөн хамгийн сүүлийн өөрийн зургийг буцаана; хүлээгдэж буй, татгалзсан эсвэл өөр байгууллагынхыг хэзээ ч үгүй. Зөвхөн өөрийн апп дотор харуулна, нийтийн хуудсанд хэзээ ч үгүй. Өөрт байгаа sha256-аа өгвөл өөрчлөгдөөгүй зураг jpeg null-тай ирнэ: байт ирэхгүй. Хоёулаа names:write эрх, hotel.notes боломж хэрэгтэй, эс бөгөөс 403 feature_off. Танай эзэмшдэггүй нэр, хасагдсан хаалга, хязгаарлагдмал газар эсвэл зөвшөөрсөн зураггүй бол 404 not_found. Нэрийг хаалганы нэртэй адил шалгаж, хүсэлт илгээхээс өмнө татгалзана.

Хэрэглээ ​

kotlin
val usage = dock.usage(days = 7)
println("${usage.caps.dailyQuota ?: 0} ${usage.days.firstOrNull()?.calls ?: 0}")

Ямар ч түлхүүрээр үнэгүй. Өдрийн квот дууссан ч хариулна. features (API 0.51.0) нь байгууллагад нээлттэй боломжуудыг A-Z дарааллаар жагсаана, жишээ нь cargo.eta. Бусад боломжийн зам 403 feature_off хариулна. Хуучин API-аас null. endpoints (API 0.62.0) нь мөн өдрүүдийн хүсэлт, олдоогүй хаалгыг зам бүрээр, их нь эхэндээ өгнө, жишээ нь GET /v1/door/:code. Хуучин API-аас null.

Хайлтын мэдээлэл хуваалцах ​

kotlin
dock.setTelemetry(true)
val hits = dock.geocode("Сансар 24")
hits.results.firstOrNull()?.let { dock.pick(it) }
val sent = dock.flushTelemetry()
println("${sent?.stored ?: 0} ${sent?.dropped ?: 0}")

Анхдагчаар унтраалттай. Хэрэглэгч зөвшөөрсний дараа л асаана, жишээ нь унтраалгаар; унтраавал унтраана. Унтраахад илгээгээгүй бүх хайлт устана. Асаалттай үед client geocode хайлт бүрээс эцсийн бичсэн текст ("Сан", "Сансар" гэж бичих явцын дуудлагууд нэг тоологдоно), үр дүнгийн тоо, pick(result)-д өгсөн үр дүн ба түүний байрыг хадгална. 50 хүрэхэд, appInBackground() дуудахад, flushTelemetry() дуудахад POST /v1/telemetry/search руу илгээнэ. appInBackground()-ийг activity-ийн onStop эсвэл ProcessLifecycleOwner observer-оос дуудна: хариуг хүлээлгүй илгээнэ. Цаг, цэг, төхөөрөмж, session илгээхгүй. API хадгалахаасаа өмнө утасны дугаар, и-мэйл хаягийг арилгана. Амжилтгүй илгээлтийг дахин оролдохгүй, төхөөрөмж дээр хадгалахгүй. Client(key, telemetry = true) нь setTelemetry(true)-тэй адил. geocode:read хэрэгтэй; нэг илгээлт нэг дуудлага. JS SDK, iOS SDK-тэй ижил дүрэм.

Сүлжээгүй хайлт ​

kotlin
val found = dock.geocode("Сансар 24")
found.results.firstOrNull()?.let { dock.pick(it) }
println("${found.offline} ${dock.places().size}")
dock.forgetPlaces()

Сүлжээтэй үед found.offline false, API хариулна. pick(result)-д өгсөн газар бүр төхөөрөмж дээр хадгалагдана, анхдагчаар асаалттай, хуваалцах асаалттай эсэхээс үл хамаарна. geocode хариу авахгүй бол (DockError код network) эдгээр газраас offline true-тэй хариулна: бичсэн үг бүр нэр, урт хэлбэр эсвэл кодын нэг үгийн эхлэл байх ёстой, том жижиг үсэг хамаарахгүй. Хамгийн их сонгосон нь эхэнд, score нь сонгосон тоо, layer 1, near null, талбарууд API-ийн сүүлд өгснөөр; дараагийн сүлжээтэй хариу тэдгээрийг шинэчилнэ. Таарах газаргүй бол network алдаа өмнөх шигээ шидэгдэнэ. Цуцалсан coroutine, API-ийн татгалзал (429, 401) хэзээ ч төхөөрөмжөөс хариулахгүй.

Хадгалах: зөвхөн газрын талбарууд (places() тэдгээрийг Place болгон өгнө). Хадгалахгүй: бичсэн текст, цаг, цэг, оноо. Анхдагчаар 100 газар (max 1-1000, үгүй бол IllegalArgumentException); хамгийн бага сонгосон нь эхэлж гарна. store өгөхгүй бол санах ойд л; гурван дуудлагатай PlaceStore өгч болно: Client(key, placeCache = PlaceCacheOptions(store = myStore)). SharedPreferences дээр: getString(key, null), edit().putString(key, value).apply(), edit().remove(key).apply(). Алдаа шидсэн эсвэл эвдэрсэн утгатай store-г үл тооно. JS SDK-тэй ижил түлхүүр (dock.places.v1), ижил формат. Эндээс dock руу юу ч илгээхгүй. placeCache = null унтраана. JS SDK, iOS SDK-тэй ижил дүрэм.

Хаягийн талбар ​

kotlin
import kotlinx.coroutines.coroutineScope

coroutineScope { // in an app: lifecycleScope or viewModelScope, on the main thread
    val field = Suggester(
        dock, this, proximity = { UB_CENTER },
        show = { items, q -> println("$q: ${items.joinToString("; ") { label(it, Lang.MN) }}") },
        fail = { error -> println("$error") },
    )
    field.input("Сансар") // from the text field's onValueChange
}

Захиалга эсвэл суух газрын маягтад нэг талбар. Suggester гурав дахь тэмдэгтээс, сүүлийн товчноос 200 ms дараа асууна (SUGGEST_MIN_CHARS, SUGGEST_DELAY_MS). Шинэ товч явж буй хүсэлтийг цуцална, тиймээс хоцорсон хариу жагсаалтыг хэзээ ч солихгүй. Барилгын код шиг уншигдах бичвэрийг (parseDoorCode) эхлээд door-оор хайж, жагсаалтын эхэнд тавина; хаалга олдохгүй код geocode руу шилжинэ. Хүсэлт таны өгсөн scope-д явна; show жагсаалт, түүний бичвэрийг тэнд авна; 3 ба түүнээс олон тэмдэгттэй үед хоосон жагсаалт нь олдсонгүй гэсэн үг. fail нь DockError авна. Мөр бүр Suggestion: Suggestion.Door эсвэл Suggestion.Result; label(item, lang) түүний бичвэрийг өгнө, албан ёсны хаягтай таараагүй бол "(албан бус)". Хүн нэгийг дарахад field.choose(item) дууд: явж буй хүсэлтийг зогсоож, geocode хариуг pick-д өгнө (сүлжээгүй хайлт, хэрэглэгч зөвшөөрсөн бол хайлт хуваалцах); кодоор олсон хаалгыг өгөхгүй. input, cancel, choose-г main thread-ээс дууд. Тохиргоо: limit (анхдагч 5), proximity (хүсэлт бүрт асууна), types (зөвхөн эдгээр төрөл, geocode-ийнх шиг: гудамж сонгогчид listOf(GeocodeType.STREET); код эсвэл хаалганы холбоосыг types-д DOOR байвал л хаалгаар хайна), minChars, delayMs. View байхгүй: жагсаалтыг өөрийн Compose LazyColumn эсвэл RecyclerView-д зур. JS SDK-ийн attachSuggest-тэй ижил дүрэм.

Аялал бичих ​

kotlin
val feed = PositionFeed()
dock.startTrace(Consent.OPT_IN, feed)
val now = System.currentTimeMillis()
feed.push(PositionFix(106.9177, 47.9186, accuracy = 8.0, timeMs = now))
feed.push(PositionFix(106.9183, 47.9189, accuracy = 8.0, timeMs = now + 5_000))
val trips = dock.stopTrace()
trips.firstOrNull()?.id?.let { id ->
    val stored = dock.trace(id)
    println("${stored.properties.points} цэг, ${stored.properties.purgeAfter} хүртэл")
    dock.deleteTrace(id)
}

startTrace(consent, source, maxAccuracyM) дуудах хүртэл унтраалттай. Хэрэглэгч энэ аяллаа хуваалцахыг зөвшөөрсний дараа л дуудна; Consent.OPT_IN цорын ганц утга. SDK байршлын зөвшөөрөл хэзээ ч асуухгүй: апп өөрөө, өөрийн тайлбартай асууна. LocationCallback (FusedLocationProviderClient) эсвэл LocationListener дотроо байршил бүрийг өгнө: feed.push(PositionFix(l.longitude, l.latitude, if (l.hasAccuracy()) l.accuracy.toDouble() else null, l.time)). Эсвэл өөрийн PositionSource-ийг өгнө. Client [lon, lat, t] хадгална: 6 оронтой бутархай, UTC бүхэл секунд, секундэд нэгээс ихгүй цэг. Орхих: maxAccuracyM-ээс (анхдагч 50 м) муу нарийвчлалтай, Монголоос гадуурх, цаг нь ухарсан цэг. Нарийвчлал, хурд, төхөөрөмж, хэрэглэгчийг хэзээ ч илгээхгүй. Цэгүүд санах ойд л байна, диск дээр хадгалахгүй. tracing бичиж байх үед true. stopTrace() аяллыг POST /v1/traces руу 20,000 цэг тутамд хувааж илгээгээд хэсэг бүрийн баримтыг буцаана. id бүрийг хадгална уу: deleteTrace(id) цэгүүдийг одоо устгана, trace(id) нь таны экспорт. 2-оос цөөн цэг бол юу ч илгээхгүй. Амжилтгүй илгээлт алдаа шидэж цэгүүдийг санах ойд үлдээнэ: дахин оролдохдоо stopTrace(), хаяхдаа cancelTrace() дуудна. Хориотой газрын доторх цэгийг хадгалахгүй. Түүхий цэгийг 90 хоногийн дараа устгана. trace:write хэрэгтэй: бичигчид аппын газрын зургийн түлхүүр биш, тусдаа түлхүүр өгнө.

Аяллын нүд ​

kotlin
val box = BBox(106.7, 47.8, 107.2, 48.0)
val own = dock.ownTraceCells("2026-10", box)
println("${own.closed} ${own.features.size} ${own.features.firstOrNull()?.properties?.trips ?: 0}")
val all = dock.traceCells("2026-09", box)
println("${all.month} ${all.features.size}")
val speeds = dock.traceSpeeds("2026-09", box)
println("${speeds.month} ${speeds.features.size} ${speeds.features.firstOrNull()?.properties?.kmH ?: 0}")
val roads = dock.traceRoads("2026-09", box)
println("${roads.month} ${roads.features.size} ${roads.features.firstOrNull()?.properties?.kmH ?: 0} ${roads.features.firstOrNull()?.geometry?.lines?.size ?: 0}")
val peak = dock.traceRoads("2026-09", box, RoadBand.AM_PEAK)
println("am_peak ${peak.features.size} ${peak.features.firstOrNull()?.properties?.kmH ?: 0}")

ownTraceCells нь таны самбар: танай байгууллагын аяллыг 500 м нүд, сараар, таны нэг ч аялал орсон нүд бүрийг өгнө, өөр байгууллагын өгөгдлийг уншихгүй. Одоогийн сарыг ч хариулна, аялал ирэх тусам өснө; сар дууссанаас хойш 14 хоногийн дараа тоо эцэслэгдэж closed нь true болно. trace:read хэрэгтэй, самбарын түлхүүрт зориулсан зөвхөн унших эрх: аялал илгээж, экспортлож, устгаж чадахгүй, trace:write нүдийг уншихгүй. traceCells нь бүх түнш хамтдаа, ижил тор: 3 ба түүнээс олон байгууллагын аялалтай, хамгийн том байгууллагыг хассаны дараа 5 ба түүнээс олон аялал үлдсэн нүд л гарна. Нүд байхгүй нь тэг биш, цөөн гэсэн үг. Туршилтын болон дотоод байгууллага тоологдохгүй. Зөвхөн бүтэн сар, сар дууссанаас хойш 14 хоногийн дараанаас (өмнө нь 400 month_open). insights:read хэрэгтэй. Хоёулаа month-ийг YYYY-MM (Улаанбаатар), Монгол доторх BBox-ийг, тал бүр 1 градусаас ихгүй (400 bad_bbox) авна. rule нь API-ийн түлхүүрүүдийг бичсэнээр нь хадгална (min_orgs). id, цаг, шугам байхгүй.

traceSpeeds нь бүх түншийн аяллын хөдөлгөөний хурдыг нүдээр өгнө, ижил тор, сар, хүрээ, ижил дүрэм. Аяллыг хадгалсан цэгүүдийн хооронд хэсэг болгон хуваана. Хоёр цэг нь 1-60 секундын зайтай, хурд нь 3-130 км/ц, дунд цэг нь аяллын эхний болон сүүлийн цэгээс 200 м-ээс хол хэсэг л тоологдоно: зогсоол, хаалга хүртэл алхсан нь орохгүй. kmH нь нүдэнд тоологдсон метрийг тоологдсон секундэд хуваасан, 0.1 хүртэл, тиймээс олон аялалтай нүд илүү жинтэй. Нүдээр: зам бүрийн хурдыг доорх traceRoads өгнө. Нүд байхгүй нь удаан зам биш, аялал цөөн гэсэн үг. Аяллын тоо байхгүй. insights:read хэрэгтэй.

traceRoads нь ижил хурдыг замаар өгнө. Аяллыг хадгалах үед Valhalla map matching-аар OSM замд тааруулна; хэсгийн хоёр цэг хоёулаа тэр замд таарсан бол traceSpeeds-ийн дүрмээр тэр замд тоологдоно. Зам бүр нэг feature: id нь OSM замын дугаар текстээр, шугам нь dock-ийн тэр дугаартай одоогийн зам, properties нь kmH (замд тоологдсон метрийг секундэд хуваасан, 0.1 хүртэл), nameMn, nameEn, highway, мэдэхгүй бол null. Шугам нь TraceRoadGeometry, LineString, зам хэсэгчилсэн бол MultiLineString; geometry.lines нь бүх хэсгийг өгнө, хоёуланг нь нэг кодоор зурна. Зам ижил дүрмээр л гарна; зам байхгүй нь удаан биш, аялал цөөн гэсэн үг. Хязгаарлалттай газрыг дайрсан зам гарахгүй. dock-ийн замын шугам ачаалагдах хүртэл хоосон. Аяллын тоо байхгүй. insights:read хэрэгтэй.

band (API 0.49.0) нь нэг цагийн бүсийн аяллыг л өгнө, аяллын эхний хадгалсан цэгийн Улаанбаатарын цагаар: RoadBand.AM_PEAK Даваа-Баасан 07:00-09:59, RoadBand.PM_PEAK Даваа-Баасан 17:00-19:59, RoadBand.OFF_PEAK бусад цаг, Бямба, Ням бүтэн. Бүс бүр ижил дүрмийг өөрийн аяллаар давна: бүх цагт гарсан зам бүсэд гарахгүй байж болно. Өгөхгүй бол бүх цаг. rule["hours"] аль нь болохыг хэлнэ.

Хаалганд хүрэх минут ​

kotlin
val arrivals = dock.ownArrivals("2026-10")
println("${arrivals.month} ${arrivals.closed} ${arrivals.trips} ${arrivals.slow} ${arrivals.median ?: 0} ${arrivals.features.size}")

ownArrivals нь таны аялал сүүлийн 200 м-т хэдэн минут зарцуулсныг өгнө: аялал бүрд, төгсгөлөөсөө 200 м-ээс сүүлчийн удаа холдсоны дараах эхний цэгээс төгсгөл хүртэлх бүтэн минут; 60 нь 60 ба түүнээс дээш. 200 м дотор эргэлдсэн нь тоологдоно; төгсгөлөөсөө 200 м-ээс хэзээ ч холдоогүй аялал тоологдохгүй. Минутад зогсоол, хаалга хүртэл алхах нь орно: сар, газрыг хооронд нь харьцуулахад хэрэглэнэ. trips, slow (5 ба түүнээс олон минут), median, p75, p90 (ойрын эрэмбэ, аялалгүй бол null) нь сарын нийт; histogram нь минут бүрийн аялал, аялалгүй минутыг орхино. features нь аялал дууссан 100 хүртэл нүд, аяллын нүдний тор дээр, удаан аяллаар, дараа нь аяллаар; cells нь бүгдийг нь тоолно. Зөвхөн танай байгууллага, өөр байгууллагын юуг ч уншихгүй. Одоогийн сарыг ч өгнө; сар дууссанаас хойш 14 хоногийн дараа closed нь true. Аяллыг устгавал тооноос гарна; түүхий цэгийг 90 хоногт арилгахад үлдэнэ. trace:read хэрэгтэй. Буруу сар бол 400 bad_month.

Аяллын цаг ​

kotlin
val hours = dock.ownHours("2026-10")
println("${hours.month} ${hours.closed} ${hours.trips} ${hours.byWeekday[0]} ${hours.byHour[9]} ${hours.slots.size}")
val all = dock.allHours("2026-09")
println("${all.month} ${all.slots.size} ${all.slots.firstOrNull()?.trips ?: 0}")
val khoroos = dock.traceKhoroos("2026-09")
println("${khoroos.month} ${khoroos.features.size} ${khoroos.features.firstOrNull()?.properties?.khoroo ?: 0}")
val myKhoroos = dock.ownKhoroos("2026-10")
println("${myKhoroos.month} ${myKhoroos.closed} ${myKhoroos.trips} ${myKhoroos.noKhoroo} ${myKhoroos.features.size}")
val myKinds = dock.ownKinds("2026-10")
println("${myKinds.month} ${myKinds.closed} ${myKinds.trips} ${myKinds.kinds.size} ${myKinds.kinds.firstOrNull()?.trips ?: 0}")

ownHours нь таны аялал хэзээ эхэлдгийг өгнө: аялал бүр нэг удаа, эхний хадгалсан цэгийнхээ Улаанбаатарын гараг (1 Даваа, 7 Ням) ба цагт (0-ээс 23) тоологдоно. trips нь сарын нийт; byWeekday нь 7 тоо, Даваагаас эхэлнэ; byHour нь 24 тоо, 0 цагаас эхэлнэ; slots нь аялалтай гараг, цаг бүр, гараг дараа нь цагаар; аялалгүйг орхино. Аялал эхэлсэн сартаа тоологдоно, ownTraceCells-тэй адил. Зөвхөн танай байгууллага, өөр байгууллагын юуг ч уншихгүй. Одоогийн сарыг ч өгнө; сар дууссанаас хойш 14 хоногийн дараа closed нь true. Аяллыг устгавал тооноос гарна; түүхий цэгийг 90 хоногт арилгахад үлдэнэ. trace:read хэрэгтэй. Буруу сар бол 400 bad_month.

allHours нь бүх түнш хамтдаа, аяллын нүдний дүрмээр: 3 ба түүнээс олон байгууллагын аялалтай, хамгийн том байгууллагыг хассаны дараа 5 ба түүнээс олон аялал үлдсэн гараг, цаг л гарна. Цаг байхгүй нь тэг биш, цөөн гэсэн үг. Нийт тоо, гараг эсвэл цагийн нийлбэр байхгүй тул орхисон цагийг тооцоолж гаргахгүй. Туршилтын болон дотоод байгууллага тоологдохгүй. Зөвхөн бүтэн сар, сар дууссанаас хойш 14 хоногийн дараанаас (өмнө нь 400 month_open). insights:read хэрэгтэй.

traceKhoroos нь бүх түншийн аялал хаана, хэдэн цагт дуусдагийг ижил дүрмээр өгнө: аялал бүр сүүлийн хадгалсан цэгийнхээ Улаанбаатарын цаг (0-23), төгсгөлийн нүдний төвийг агуулсан хороонд нэг удаа тоологдоно. Хороо бүр нэг feature: полигон, districtMn, districtEn, хорооны дугаар, дүрмийг давсан цаг бүр hours. Цаг байхгүй нь тэг биш, цөөн гэсэн үг. Хорооны нийт тоо байхгүй. Зөвхөн одоогийн хорооны полигон; полигонгүй хороо гарахгүй. Зөвхөн бүтэн сар, сар дууссанаас хойш 14 хоногийн дараанаас (өмнө нь 400 month_open). insights:read хэрэгтэй.

ownKhoroos нь таны аялал хаана, хэдэн цагт дуусдагийг хороо, ирсэн цагаар өгнө, traceKhoroos-тэй адил уншина, гэхдээ бүлгийн дүрэмгүй: аялал таных. trips нь сарын нийт, noKhoroo нь одоогийн хорооны полигонд ороогүй аялал, feature бүрт хорооны trips, аялалтай цаг бүр. trips нь noKhoroo ба бүх хорооны аяллын нийлбэр. Хорооны полигон ачаалагдах хүртэл бүх аялал noKhoroo-д. Зөвхөн танай байгууллага. Одоогийн сарыг ч өгнө; сар дууссанаас хойш 14 хоногийн дараа closed нь true. trace:read хэрэгтэй. Буруу сар бол 400 bad_month.

ownKinds нь таны аялал ямар барилгад дуусдагийг өгнө: аялал бүр нэг удаа, сүүлийн хадгалсан цэгийг агуулсан барилга, эсвэл 30 м доторх хамгийн ойр барилга, аялал хадгалагдах үеийн тэр барилгын төрлөөр (apartment, ger_house, commercial, public, industrial, garage, other). unknown нь төрөлгүй барилга, none нь 30 м дотор барилга байхгүй. Хязгаарлалттай газрын барилгыг уншихгүй. trips нь сарын нийт, бүх төрлийн trips-ийн нийлбэр; kinds нь аялалтай төрлүүд, ихээс нь. Зөвхөн танай байгууллага, бүлгийн дүрэмгүй. Одоогийн сарыг ч өгнө; сар дууссанаас хойш 14 хоногийн дараа closed нь true. trace:read хэрэгтэй. Буруу сар бол 400 bad_month.

Алдаа ​

kotlin
try {
    dock.door("00000")
} catch (e: DockError) {
    when {
        e.code == "not_found" -> println("ийм кодтой хаалга алга")
        e.retryAfter != null -> println("${e.retryAfter} секунд хүлээ")
        else -> println("${e.status} ${e.code} ${e.message}")
    }
}

status нь HTTP статус, code нь API-ийн error (invalid_code, not_found, retired_code, rate_limited, quota_exceeded, miss_cap, ...). Хариу ирээгүй бол status 0, code network. retryAfter нь 429, 503 үед секундээр, бусад үед null. SDK өөрөө дахин оролдохгүй. Coroutine цуцлалт дамжин гарна.

Газрын зураг ​

kotlin
val style = dock.styleJson(StyleOptions(building = "#1f5c8f"))
val saved = dock.styleUrl("st_7m4xq2b9kd")
println(java.net.URI(saved).path)

styleJson(options) нь dock-ийн загварыг MapLibre style JSON болгож өгнө: дэвсгэр, барилга, итгэлцлээр будсан хаалга. JS SDK-ийн dockStyle-тэй ижил загвар. Хоёр тайлын эх үүсвэр нь таны түлхүүртэй. styleUrl(id) нь загварын засварлагчид хадгалсан загварын URL-ийг түлхүүртэй өгнө; id нь st_ ба 10 тэмдэгт биш бол IllegalArgumentException шиднэ. API эдгээр URL-ийн түлхүүрийг тайлын URL руу дамжуулдаг тул MapLibre Native-д хүсэлт сольдог interceptor хэрэггүй. Хоёр мөр хоёулаа түлхүүртэй: log-д бүү бич.

kotlin
// app build.gradle.kts: implementation("org.maplibre.gl:android-sdk:13.6.1") dock-ийн мөрийн хажууд
MapLibre.getInstance(this)
mapView.getMapAsync { map ->
    map.setStyle(Style.Builder().fromJson(dock.styleJson()))
    map.cameraPosition = CameraPosition.Builder().target(LatLng(UB_CENTER.lat, UB_CENTER.lon)).zoom(15.0).build()
}

MapLibre Native Android 13 нь Android 6 (API 23) шаардана; энэ SDK API 21-ээс ажиллана. Хувилбар бүр хоёр загварыг Android 16 эмулятор дээр MapLibre Native 13.6.1-ийн OpenGL ES (android-sdk-opengl), Vulkan (android-sdk) хоёр хувилбараар зурж, өнгө болон зурсан GPU драйверыг шалгадаг. dock-ийн барилга, хаалгыг өөрийн суурь загвар дээр тавих бол dockSources(baseUrl), dockLayers(options)-ийг нэмж, эх үүсвэрийг authorizedUrl()- ээр түлхүүрлэнэ. tileJsonUrl(source) нь building эсвэл entrance-ийн TileJSON URL-ийг түлхүүргүй өгнө; authorizedUrl() зөвхөн dock-ийн URL-д access_token нэмнэ, бусад URL хэвээр буцна.

Хуучирсан зам ​

kotlin
val logged = Client("dk_...", onDeprecation = { n -> println("${n.route} ${n.sunset ?: "-"}") })

Хариу нь зам хуучирсан гэвэл (Төлөв-ийг харна), client onDeprecation-ийг зам бүрд нэг удаа route (загвар, URL хэзээ ч биш), deprecated, sunset, link-тэй дуудна. Анхдагч нь зам бүрд нэг мөр хэвлэнэ. Өнөөдөр хуучирсан зам алга.

Сүлжээ ​

Анхдагч нь UrlConnectionTransport (HttpURLConnection). OkHttp эсвэл өөрийн client ашиглах бол transport-д DockTransport өгнө: method, URL, толгой, биеийг авч, хариу ирээгүй бол IOException шиднэ. Android дээр энгийн http (дотоод stack) network security config шаардана; https://geo.dock.mn шаардахгүй.

Түлхүүр ​

Түлхүүр зөвхөн Authorization толгойд, access_token зөвхөн authorizedUrl()-ийн URL-д явна. Client эсвэл хүсэлтийн toString() нь зөвхөн үндсэн URL, эсвэл method ба URL-ийг харуулна. Апп түлхүүрээ хэрэглэгч бүрд хүргэнэ: зөвхөн tiles:read, geocode:read, door:read өгнө.

Лавлах ​

Төрөл, гарын үсэг бүр тайлбартайгаа, кодоос бичигдсэн: Android SDK лавлах.

Нэр
ClientClient(key, baseUrl, transport, onDeprecation, telemetry, placeCache). Түлхүүрийг хадгална. Буруу түлхүүрт DockError шиднэ.
geocode(q, limit, proximity, types)Нэр, хаягаас газрууд, хамгийн тохирох нь эхэнд. proximity: ижил таарцтай нэрсээс ойр нь эхэнд. types (GeocodeType) нь зөвхөн тэр төрлүүдийг үлдээнэ, limit-ээс өмнө сонгоно. geocode:read.
reverse(point, radius, limit, types)Цэг дээрх, ойрын газрууд, ойр нь эхэнд, дүүрэг, хороотой. types (ReverseType) нь зөвхөн тэр төрлүүдийг үлдээнэ, limit-ээс өмнө сонгоно. geocode:read.
nearby(point, categories, radius, limit)Цэгийн ойрын эдгээр ангиллын газрууд, ойр нь эхэнд, ангилал, зайтай. categories (NearbyCategory) нэг бүрийг нэг удаа, өгсөн дарааллаар; хоосон бол хүсэлтгүйгээр 400 invalid_category. Дэлгүүр code null: "код алга" ба албан хаягийг харуулна. geocode:read.
door(code, unit)Кодоор хаалга. door:read.
route(from, to, mode, departAt, via)Цэг эсвэл кодын хоорондох зам, код бол хаалга хүртэл, via-г дарааллаар дайрна. route:read.
isochrone(from, contoursMinutes, mode)Нэг төгсгөлөөс 60 хүртэл минутын 1-4 хугацаанд хүрэх талбай, GeoJSON-оор. route:read.
matching(coordinates, timestamps, mode)GPS мөрийг явсан замууд дээр нь, тасраагүй хэсэг бүрт нэг шугам, цэг бүрт нэг байрлал. 2-оос MATCHING_MAX (100) цэг. route:read.
optimizedTrips(stops, roundtrip, mode)Зогсоолуудыг замд хамгийн бага хугацаа зарцуулах дарааллаар, тэр дарааллаарх аялал. 2-оос OPTIMIZED_TRIPS_MAX (12) зогсоол. route:read.
tilequery(point, sources, radius, limit, geometry)Цэг дээрх эсвэл ойрхон байгаа байшин, хаалга, хамгийн ойроос нь, GeoJSON. Radius TILEQUERY_RADIUS_MAX_M (1000) м хүртэл, TILEQUERY_LIMIT_MAX (50) объект хүртэл. tiles:read.
matrix(from, to, mode)from бүрээс to бүр хүртэлх хугацаа, зай нэг дуудлагаар, тал бүр MATRIX_MAX (10) хүртэл. route:read.
place(id)Газрыг id-гаар дахин, parents-тэй. geocode:read.
changes(since, limit, cursor)[since, until) хооронд өөрчлөгдсөн id-ийн нэг хуудас. changes:read.
confirm(confirmation)Газар дээрх жолооч хаалгыг баталж, эсвэл өөр газар, алга гэж хэлнэ. confirm:write.
ownConfirmations(month)Таны жолоочийн баталгаа, хаалганы мэдэгдэл сараар, үр дүн ба өдрөөр, алдаатай цэгтэй; эцэслэгдсэн бол closed. confirm:read.
closures()Өнөөдөр дуусаагүй зам хаалт, тус бүр хүрээтэй. route:read.
reportClosure(report, idempotencyKey)Явах боломжгүй зам, гарцыг мэдэгдэнэ; idempotencyKey дахин илгээхийг аюулгүй болгоно. closures:write.
closure(id)Өөрийн нэг хаалтын мэдэгдэл, тэмдэглэлтэй. closures:write.
liftClosure(id, on)Зам on өдрөөс дахин нээгдсэн, null бол өнөөдөр. closures:write.
excludePolygons(closures, day)Офлайн: аяллын өдөр идэвхтэй хаалтын хүрээ, Valhalla-ийн exclude_polygons-д. ClosuresOverLimitException шиднэ.
ExcludePolygons.closureAt(point)Офлайн: цэгийг хүрээндээ агуулсан хаалтын id, үгүй бол null.
crossingsOnRoute(crossings, line, month)Офлайн: хээрийн багцын crossings.geojson-оос аяллын шугамын өнгөрөх гарам, гүүргүй огтлолцол, тухайн сарын их ус.
LOW_FLOW_CONFIDENCE0.1. Урсацын confidence үүнээс ихгүй бол monthM3s нь null.
PackCrossings.fromJson(text)Багцын crossings.geojson файлын текст.
ubMonth()Улаанбаатарын энэ сар, 1-12.
poisOnRoute(pois, line, nearM)Офлайн: хээрийн багцын pois.geojson-оос аяллын шугамаас nearM дотор орших бүртгэлтэй шатахуун түгээх станц, гэр бааз, бүртгэлгүйн тоо.
POI_NEAR_M2000.0, poisOnRoute-ийн анхдагч nearM, м.
wetlandsOnRoute(wetlands, line)Офлайн: хээрийн багцын wetlands.geojson-оос аяллын явах OSM-ийн намгархаг газрын хэсгүүд, эхнээс болон хэсэг дээрх метр.
WETLAND_MIN_ON_M20.0, м: хэсгийн үүнээс бага хэсгээр явах аялал зөвхөн хөндлөн гарна, хэсэг бүхэлдээ биш бол.
passesOnRoute(passes, line)Офлайн: хээрийн багцын passes.geojson-оос аяллын гарах OSM-ийн уулын даваанууд, эхнээс болон шугамаас хэдэн метр, OSM ба DEM өндөр, тус бүрийн хамгийн их нь, хоёр нь зөрөх газар.
sandOnRoute(sand, line)Офлайн: хээрийн багцын sand.geojson-оос аяллын явах OSM-ийн элсэн газрын хэсгүүд, эхнээс болон хэсэг дээрх метр.
SAND_MIN_ON_M20.0, м: хэсгийн үүнээс бага хэсгээр явах аялал зөвхөн хөндлөн гарна, хэсэг бүхэлдээ биш бол.
waterOnRoute(water, line, nearM)Офлайн: хээрийн багцын water.geojson-оос аяллын шугамаас nearM (өгөхгүй бол багцынх, 2000 м) дотор OSM-ийн худаг, булаг, цорго, ундны ус, эхнээс болон шугамаас хэдэн метр, уух эсэхийг OSM юу гэж бичсэн.
basemapStyle(basemap, url, options)Офлайн: хээрийн багцын basemap.pmtiles-д зориулсан MapLibre-ийн бүтэн загвар, JS SDK-тай ижил JSON.
PackBasemap.fromManifest(text)Багцын manifest.json-ийн basemap хэсэг, байхгүй бол null.
BASEMAP_EXCLUDEDpoi, housenumber: суурь зурагт байж болохгүй давхаргууд.
PackPois.fromJson(text)Багцын pois.geojson файлын текст.
checkPack(manifest, directory)Офлайн: хээрийн багцын manifest-д жагсаасан файл бүрийг багцын хавтаснаас хэмжээ, sha256-аар; файл бүрийн төлөв: OK, MISSING, BYTES, SHA256. Зогсоно: Dispatchers.IO дээр дууд.
PackManifestFiles.fromJson(text)Багцын manifest.json файлын текст; зөвхөн files-ийг уншина.
packRoute(manifest, stops, day, closures)Офлайн: хээрийн багц дээрх маршрутын Valhalla хүсэлт: manifest-ийн costing, аяллын өдрийн хаалт exclude_polygons-д, км; тойрсон хаалт, attribution, confidenceNote, багцад аяллын оноо байхгүй үед traceNote; manifest-д үг байвал багцын үгээр. IllegalArgumentException, ClosuresOverLimitException, EndInClosureException шиднэ.
PackRouteManifest.fromJson(text)Багцын manifest.json файлын текст; costingOptions түлхүүрээ бичсэнээр нь хадгална.
PACK_TRACE_NOTE, PACK_TRACE_NOTE_MNБагцад аяллын оноо байхгүй үед (confidence osm_only) хэлэх үг.
SuggesterХаягийн талбар: Suggester(client, scope, limit, proximity, types, minChars, delayMs, show, fail), дараа нь өөрчлөлт бүрт input(text), дарахад choose(item), cancel(). Main thread.
SuggestionБичсэн кодоос Suggestion.Door(door), эсвэл Suggestion.Result(result). label(item, lang) уншина.
SUGGEST_MIN_CHARS, SUGGEST_DELAY_MS3, 200.
parseDoorCode(text)Офлайн: бичсэн эсвэл буулгасан барилгын кодыг API-тай адил уншина, DoorCodeInput.Code(code, unit) эсвэл DoorCodeInput.Invalid(error, reason).
doorLink(text, unit)Офлайн: хаалгыг хуваалцах холбоос, https://map.dock.mn/d/7QSVX?u=17, бичвэр код болж чадахгүй бол null.
parseDoorLink(text)Офлайн: бичвэр дэх эхний хаалганы холбоос, кодыг болон дугаарыг parseDoorCode шиг уншина, холбоосгүй бол null.
DOOR_LINK_BASE"https://map.dock.mn/d/".
doorQr(text, unit)Офлайн: хаалганы холбоосын QR, DoorQr(link, version, size, modules), бичвэр код болж чадахгүй бол null.
doorQrSvg(text, unit, px, margin)Офлайн: тэр QR SVG бичвэр болж, px модуль бүрд (4.0), margin цагаан модуль (4), эсвэл null.
doorQrPixels(text, unit, px, margin)Офлайн: тэр QR Bitmap-д зориулсан DoorQrPixels(link, side, argb), px пиксел модуль бүрд (8), margin (4), эсвэл null.
DOOR_CODE_ALPHABET, DOOR_CODE_LENGTHКодод орох 30 тэмдэгт, 5.
reportDoor(report)Буруу, алга, давхар, зураглагдаагүй хаалга мэдэгдэх. door:read.
usage(days)Байгууллагын хязгаар, сүүлийн 1-90 өдөр.
tileJsonUrl(source)building эсвэл entrance-ийн TileJSON URL, түлхүүргүй.
authorizedUrl(url)dock-ийн URL-д access_token нэмнэ, MapLibre Native-д.
styleJson(options)dock-ийн загвар MapLibre style JSON-оор, эх үүсвэр нь түлхүүртэй. Style.Builder().fromJson-д.
styleUrl(styleId)Хадгалсан загварын URL, түлхүүртэй. Style.Builder().fromUri-д.
StyleOptionsbackground, building, buildingOutline өнгө, extrude (анхдагч false).
dockStyle(baseUrl, options), dockSources(baseUrl), dockLayers(options)Загвар, түүний эх үүсвэр, давхаргууд, түлхүүргүй.
UB_CENTERСүхбаатарын талбай, LonLat(106.9177, 47.9186).
setTelemetry(on)Хайлтын мэдээллийг хэрэглэгчийн сонголтоор асаах, унтраах. Унтраахад хүлээж буй нь устана.
pick(result)Хэрэглэгч энэ geocode үр дүнг сонгосон. Сүлжээгүй хайлтад хадгална; хуваалцах асаалттай үед л илгээнэ.
places()Энэ төхөөрөмж дээр сонгосон газрууд, хамгийн их сонгосон нь эхэнд.
forgetPlaces()Тэдгээрийг санах ой, store-оос мартана.
PlaceCacheOptionsmax (анхдагч 100), store.
PlaceStoreГурван дуудлага: getString(key), putString(key, value), remove(key).
PlaceХадгалсан газар: score, layer, near-гүй GeocodeResult-ийн талбарууд.
flushTelemetry()Хүлээж буй хайлтыг одоо илгээнэ. Унтраалттай эсвэл хоосон бол null.
appInBackground()Хүлээж буй хайлтыг хариу хүлээлгүй илгээнэ. onStop-оос дуудна.
startTrace(consent, source, maxAccuracyM)Хэрэглэгч зөвшөөрсний дараа аялал бичиж эхэлнэ.
stopTrace()Зогсоож аяллыг илгээнэ. 20,000 цэг тутамд нэг TraceReceipt. trace:write.
cancelTrace()Зогсоож аяллыг илгээлгүй хаяна.
tracingАялал бичиж байх үед true.
trace(id)Таны нэг аялал, хадгалсан хэлбэрээр, GeoJSON. trace:write.
deleteTrace(id)Аяллын цэгүүдийг одоо устгана. trace:write.
ownTraceCells(month, bbox)Өөрийн аяллыг 500 м нүд, сараар, нэг ч аялалтай нүд бүр; эцэслэгдсэн бол closed. trace:read.
ownArrivals(month)Таны аяллын сүүлийн 200 м-ийн минут сараар: median, p75, p90, минут ба төгсгөлийн нүдээр; эцэслэгдсэн бол closed. trace:read.
ownHours(month)Таны аялал сараар, гараг ба цагаар, эхний цэгийн Улаанбаатарын цагаар; эцэслэгдсэн бол closed. trace:read.
allHours(month)Бүх түншийн аяллыг гараг ба цагаар, нийтэлсэн сар, 3 ба түүнээс олон байгууллагатай цаг л. insights:read.
traceCells(month, bbox)Бүх түншийн аяллыг нүдээр, нийтэлсэн сар, 3 ба түүнээс олон байгууллагатай нүд л. insights:read.
traceSpeeds(month, bbox)Бүх түншийн хөдөлгөөний хурдыг нүдээр, нийтэлсэн сар, 3 ба түүнээс олон байгууллагатай нүд л. insights:read.
traceRoads(month, bbox, band)Бүх түншийн хөдөлгөөний хурдыг замаар, нийтэлсэн сар, 3 ба түүнээс олон байгууллагатай зам л; band нэг цагийн бүс. insights:read.
traceKhoroos(month)Бүх түншийн аяллыг хороо ба ирсэн цагаар, нийтэлсэн сар, 3 ба түүнээс олон байгууллагатай цаг л. insights:read.
ownKhoroos(month)Таны аялал сараар, хороо ба ирсэн цагаар, хороонд ороогүйг тусад нь; эцэслэгдсэн бол closed. trace:read.
ownKinds(month)Таны аялал сараар, дууссан барилгын төрлөөр, ихээс нь; эцэслэгдсэн бол closed. trace:read.
PositionFeedБайршлын callback-аас PositionFix өгөх PositionSource.
PositionFixНэг байршил: lon, lat, accuracy, timeMs (Location.getTime() шиг). Зөвхөн lon, lat, цаг илгээгдэнэ.
ConsentConsent.OPT_IN, хэрэглэгч зөвшөөрсөн. Цорын ганц утга.
DockErrorБүх алдаа: status, code, message, retryAfter.
DockTransportНэг suspend арга, send(request: HttpRequest): HttpResponse. Анхдагч UrlConnectionTransport.
label(place, lang)Хаалга, газрыг хүнд харуулах текст, таараагүй бол "(албан бус)". JS-тэй ижил дүрэм.
LangLang.MN эсвэл Lang.EN.
IDEMPOTENCY_KEY_REIdempotency-Key-ийн хэлбэр: үсэг, тоо, ._:--ээс 1-64 тэмдэгт.
isValidKey(key)Түлхүүрийн хэлбэр: dk_ ба 32 тэмдэгт.
DOCK_SDK_VERSION"0.65.0".

Хариуны төрөл бүр (Door, GeocodeResponse, Route, UsageResponse, ...) ./gradlew test-д API лавлах-тай талбар бүрээр шалгагдана. Энэ хуудасны хоёр Gradle файлаас бусад код тэнд хуурамч transport дээр ажиллана. Хувилбар бүр мөн Android эмулятор дээр, API 21 ба API 36, SDK-г Maven репозиториос авдаг Android Gradle Plugin-оор бүтээсэн апп дотор ажиллана: барилгын код, зам хаалтын хүрээ, голын гарам, дотоод сервертэй HttpURLConnection, хайлтын telemetry, эмуляторын GPS-ээс LocationManager, PositionFeed-ээр бичсэн аялал. Jar дахь дуудлага бүрийг бүтээх үед API 21-тэй тулгаж шалгана.