```
package hello

import android.text.format.DateFormat
import eu.kanade.tachiyomi.source.online.HttpSource
import okhttp3.CacheControl
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.Request
import okhttp3.Response
import org.json.JSONArray
import org.json.JSONObject
import java.net.URLEncoder
import java.security.MessageDigest
import java.text.SimpleDateFormat
import java.util.ArrayList
import java.util.Date
import java.util.Locale
import java.util.concurrent.TimeUnit.MINUTES

class Manhuaren {
    override val lang = "zh"
    override val supportsLatest = true
    override val name = "漫画人"
    override val baseUrl = "http://mangaapi.manhuaren.com"

    private val pageSize = 20
    private val baseHttpUrl = baseUrl.toHttpUrlOrNull()!!

    private val c = "4e0a48e1c0b54041bce9c8f0e036124d"
    private val cacheControl: CacheControl by lazy { CacheControl.Builder().maxAge(10, MINUTES).build() }

    private fun generateGSNHash(url: HttpUrl): String {
        var s = c + "GET"
        url.queryParameterNames.toSortedSet().forEach {
            if (it != "gsn") {
                s += it
                s += urlEncode(url.queryParameterValues(it)[0])
            }
        }
        s += c
        return hashString("MD5", s)
    }

    private fun myGet(url: HttpUrl): Request {
        val now = DateFormat.format("yyyy-MM-dd+HH:mm:ss", Date()).toString()
        val realUrl = url.newBuilder()
            .setQueryParameter("gsm", "md5")
            .setQueryParameter("gft", "json")
            .setQueryParameter("gts", now)
            .setQueryParameter("gak", "android_manhuaren2")
            .setQueryParameter("gat", "")
            .setQueryParameter("gaui", "191909801")
            .setQueryParameter("gui", "191909801")
            .setQueryParameter("gut", "0")
        return Request.Builder()
            .url(realUrl.setQueryParameter("gsn", generateGSNHash(realUrl.build())).build())
            .headers(headers)
            .cacheControl(cacheControl)
            .build()
    }

     fun headersBuilder() = Headers.Builder().apply {
        add("X-Yq-Yqci", "{\"le\": \"zh\"}")
        add("User-Agent", "okhttp/3.11.0")
        add("Referer", "http://www.dm5.com/dm5api/")
        add("clubReferer", "http://mangaapi.manhuaren.com/")
    }

    private fun hashString(type: String, input: String): String {
        val hexChars = "0123456789abcdef"
        val bytes = MessageDigest
            .getInstance(type)
            .digest(input.toByteArray())
        val result = StringBuilder(bytes.size * 2)

        bytes.forEach {
            val i = it.toInt()
            result.append(hexChars[i shr 4 and 0x0f])
            result.append(hexChars[i and 0x0f])
        }

        return result.toString()
    }

    private fun urlEncode(str: String?): String {
        return URLEncoder.encode(str, "UTF-8")
            .replace("+", "%20")
            .replace("%7E", "~")
            .replace("*", "%2A")
    }

    fun popularMangaRequest(page: Int): Request {
        val url = baseHttpUrl.newBuilder()
            .addQueryParameter("subCategoryType", "0")
            .addQueryParameter("subCategoryId", "0")
            .addQueryParameter("start", (pageSize * (page - 1)).toString())
            .addQueryParameter("limit", pageSize.toString())
            .addQueryParameter("sort", "0")
            .addPathSegments("/v2/manga/getCategoryMangas")
            .build()
        return myGet(url)
    }

    fun latestUpdatesRequest(page: Int): Request {
        val url = baseHttpUrl.newBuilder()
            .addQueryParameter("subCategoryType", "0")
            .addQueryParameter("subCategoryId", "0")
            .addQueryParameter("start", (pageSize * (page - 1)).toString())
            .addQueryParameter("limit", pageSize.toString())
            .addQueryParameter("sort", "1")
            .addPathSegments("/v2/manga/getCategoryMangas")
            .build()
        return myGet(url)
    }

   fun searchMangaRequest(page: Int, query: String): Request {
        var url = baseHttpUrl.newBuilder()
            .addQueryParameter("start", (pageSize * (page - 1)).toString())
            .addQueryParameter("limit", pageSize.toString())
        if (query != "") {
            url = url.addQueryParameter("keywords", query)
                .addPathSegments("/v1/search/getSearchManga")
            return myGet(url.build())
        }
        url = url.addPathSegments("/v2/manga/getCategoryMangas")
        return myGet(url.build())
    }

    private fun getChapterName(type: String, name: String, title: String): String {
        return (if (type == "mangaEpisode") "[番外] " else "") + name + (if (title == "") "" else ": $title")
    }
}
```
please help translate this kotlin file to nodejs