Category: Blog

  • abbreviate

    abbreviate

    Shorten your strings using common abbreviations.

    ko-fi

    codecov godoc report card

    GitHub watchers GitHub stars Twitter URL

    Supported by Tidelift

    Motivation

    This tool comes out of a frustration of the name of resources (in my specific case, AWS stack names) being too long. Wouldn’t it be nice if we could have a tool that would be able to suggest shorter alternatives if your original name is too long.

    Before we get any further, I’m really interested in how you feel about this tool. Please take the time to fill in this short survey: https://forms.gle/6xV1gB8yKGdmuHJ78

    Installation

    go get github.com/dnnrly/abbreviate
    make build

    Usage

    This tool will attempt to shorten the string provided using common abbreviations
    specified by language and 'set'. Word boundaries will be detected using title case
    and non-letters.
    
    Hosted on Github - https://github.com/dnnrly/abbreviate
    
    I'm really interested in how you feel about this tool. Please take the time to fill
    in this short survey:
    https://forms.gle/6xV1gB8yKGdmuHJ78
    
    If you spot a bug, feel free to raise an issue or fix it and make a pull
    request. We're really interested to see more abbreviations added or corrected.
    
    Usage:
      abbreviate [action] [flags]
      abbreviate [command]
    
    Available Commands:
      camel       Abbreviate a string and convert it to camel case
      help        Help about any command
      kebab       Abbreviate a string and convert it to kebab case
      original    Abbreviate the string using the original word boundary separators
      pascal      Abbreviate a string and convert it to pascal case
      print       Print abbreviations in this set
      separated   Abbreviate a string and convert it using separator passed
      snake       Abbreviate a string and convert it to snake case
    
    Flags:
      -c, --custom string     Custom abbreviation set
          --from-front        Shorten from the front
      -h, --help              help for abbreviate
      -l, --language string   Language to select (default "en-us")
          --list              List all abbreviate sets by language
      -m, --max int           Maximum length of string, keep on abbreviating while the string is longer than this limit
      -n, --newline           Add newline to the end of the string (default true)
      -s, --set string        Abbreviation set (default "common")
          --no-stopwords      Remove stopwords from abbreviation
          --strategy string   Abbreviation strategy (default "lookup")
    
    Use "abbreviate [command] --help" for more information about a command.
    

    Examples:

    $ abbreviate original strategy-limited
    stg-ltd
    
    $ abbreviate original prestrategy-limitedment
    prstg-ltdmnt
    
    $ abbreviate original --max 11 strategy-limited
    strategy-ltd
    
    $ abbreviate original --max 11 --from-front strategy-limited
    stg-limited
    
    $ abbreviate camel --max 99 strategy-limited
    strategyLimited
    
    $ abbreviate kebab StrategyLimited
    stg-ltd
    
    $ abbreviate separated StrategyLimited --separator +
    stg+ltd
    
    $ abbreviate separated StrategyLimited
    stgltd
    

    Code of Conduct

    This project adheres to the Contributor Covenant code of conduct. By participating, you are expected to uphold this code.

    Contributing

    Pull requests are welcome. See the contributing guide for more details.

    Please make sure to update tests as appropriate.

    github.com/dnnrly/abbreviate for enterprise

    Available as part of the Tidelift Subscription

    The maintainers of github.com/dnnrly/abbreviate and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. Learn more.

    License

    Apache 2

    Visit original content creator repository https://github.com/dnnrly/abbreviate
  • fix-lwjgl

    fix-lwjgl

    Fix which LWJGL (Light Weight Java Game Library) version is used in Minecraft for ARM devices

    pre-commit.ci status pre-commit code style: black Ruff

    Description

    This script is a wrapper for launching Minecraft on devices that aren’t properly supported by Mojang, such as computers with ARM processors like the Raspberry Pi 3 and 4, as well as Apple’s new M series chips. On these devices, the wrong version of LWJGL is downloaded, preventing minecraft from launching properly. This program takes the arguments that would have been used to run Minecraft and rewrites a few details about LWJGL, pointing minecraft to use a user-specified folder as the LWJGL library path for the shared object files and in the case of LWJGL 3, changing the java class path information to use the correct files for your machine.

    Basically, it means minecraft works now!

    Testing

    This program has been tested successfully with ATLauncher on a Raspberry Pi 4 running 64 bit Raspberry Pi OS bullseye. It should work for 32 bit Raspberry Pi OS bullseye, but I have not tested that yet.

    Success testimonials

    The following ARM64 platforms have run Minecraft successfully with this script:

    This script might also work other platforms with arm processors, but may require minor changes.

    If possible, if this script works on anything not listed as tested, please tell me using the discussions page!

    Installation

    Ensure Python 3 is installed on your computer, and use pip to install this project with the command listed below:

    pip install git+https://github.com/CoolCat467/fix-lwjgl.git
    

    Installation on MacOS

    If you are using MacOS, you will probably have to install homebrew to install pipx (use the links given, not copying their install instructions here because they will get out of date).

    After pipx is installed, you can use the following command to install:

    pipx install git+https://github.com/CoolCat467/fix-lwjgl.git
    

    About Installation

    On default, all LWJGL files are expected to be in $HOME/.local/share/fix_lwjgl/lwjgl_{lwjgl_version}{system_arch}, so if the script was run on Raspberry Pi OS 32 bit, it would be lwjgl_3arm32. If this folder does not exist or files are missing (only checks in LWJGL 3 mode), the folder is created and all required files are downloaded from https://build.lwjgl.org/ (browse at https://www.lwjgl.org/browse) (see also can_download in configuration)

    If this script needs the LWJGL 2 folder, it will download the folders in this repository. If this script needs any LWJGL 3 modules, it will download them from LWJGL’s build repository available to browse at https://www.lwjgl.org/browse

    Configuration

    All configuration files should be located in ~/.config/fix_lwjgl/fix_lwjgl_config.ini. The current options as of writing include:

    • lwjgl_base_path – Controls where the lwjgl folders are expected to live at (defaults to $HOME/.local/share/fix_lwjgl)
    • can_download – If the wrapper is allowed to download files from the internet (defaults to True)
    • download_timeout – Timeout in seconds for downloading files from the internet (defaults to 15 seconds)

    Usage

    Go to your Minecraft launcher, and somewhere in settings is likely the ability to set a “wrapper command”. Set it to fix_lwjgl_wrapper after you install the script and everything should be good.

    On Raspberry Pi OS bullseye and some other platforms, it might be useful to have this “pre-launch” command if you are experiencing crashes:

    export MESA_GL_VERSION_OVERRIDE=4.2COMPAT

    This tells mesa gl to pretend it’s OpenGL 4.2, which stops Minecraft from trying to do some things that might cause crashes.

    You might also want to try changing it from 4.2COMPAT to 4.3 or 4.5, this is known to fix the “Could not initialize class com.mojang.blaze3d.systems.RenderSystem” issue

    Problems

    If you encounter any issues regarding this program, please check and see if anyone else is having the same issue before making a new issue. When posting your issue, be sure to include any relevant logs and what operating system you’re using and what architecture your computer’s processor uses.

    Additionally, re-running Minecraft with the additional arguments

    -Dorg.lwjgl.util.DebugLoader=true -Dorg.lwjgl.util.Debug=true
    

    might help diagnose your issue. Just be sure to remove them after everything is fixed, because OpenGL errors cause crashes in debug mode instead of just being silently ignored.

    Links

    License


    Code and documentation are available according to the MIT License (see LICENSE).

    Visit original content creator repository https://github.com/CoolCat467/fix-lwjgl
  • kotlin-common

    Kotlin่ฏญ่จ€ๅŸบไบŽMvp+Retrofit+RxJavaๅฐ่ฃ…็š„Android้กน็›ฎ็š„ๅŸบ็ก€ไพ่ต–ๅบ“

    ๅ‰่จ€

    ่ฏฅLibraryๆ˜ฏๅŸบไบŽKotlin่ฏญ่จ€ๅฐ่ฃ…็š„ไธ€ไธชๅบ“๏ผŒไธป่ฆๆ˜ฏ็”จๆฅๅˆ›ๅปบไธ€ไธชkotlin้กน็›ฎๆ—ถ๏ผŒไฝœไธบ้กน็›ฎ็š„็ฎ€ๅ•ๅฐ่ฃ…๏ผŒไฝฟ็”จ่ฏฅLibraryไฝœไธบไพ่ต–ๅผ•ๅ…ฅ๏ผŒๅณๅฏ่ฟ›่กŒ้กน็›ฎๅผ€ๅ‘๏ผŒ็œๅŽปไธ€ไบ›ๅ‰ๆœŸๅ‡†ๅค‡ๅทฅไฝœใ€‚

    ่ฏฅLibraryไธป่ฆ่ฟ›่กŒไบ†ไธ€ไธ‹ๅฐ่ฃ…๏ผš

    1. ้‡‡็”จๆ™ฎ้€šMVCๆžถๆž„็š„ๆ–นๅผ๏ผŒๅฏนActivity๏ผŒFragment,Adapterๅ’Œไธ€ไบ›ๅทฅๅ…ท็ฑป็š„ๅฐ่ฃ…ไปฅๅŠ่‡ชๅฎšไน‰View็š„ๅฎž็Žฐ๏ผ›
    2. ้‡‡็”จRetrofit+RxJava ๅฏนhttp่ฏทๆฑ‚่ฟ›่กŒ็›ธๅบ”็š„ๅฐ่ฃ…๏ผŒๅฏ่ฎพ็ฝฎๅ…ฌๅ…ฑๅ‚ๆ•ฐ๏ผŒๅนถๅฏนRX็”Ÿๅ‘ฝๅ‘จๆœŸ่ฟ›่กŒๅค„็†๏ผ›
    3. ้‡‡็”จMVPๆžถๆž„๏ผŒๅฏนไธŠ้ขๅฐ่ฃ…็š„Activity๏ผŒFragment ่ฟ›่กŒไบŒๆฌกๅฐ่ฃ…๏ผ›
    4. ่ฏฅ้กน็›ฎไฝฟ็”จไบ†org.jetbrains.anko ๏ผŒๅฏๅฎž็Žฐๅฏนๅธƒๅฑ€ๆ–‡ไปถ็š„่‡ชๅŠจไพ่ต–ๆณจๅ…ฅ๏ผŒkotlinๆ–‡ไปถไธญ็š„Viewๅ็งฐๅฐฑๆ˜ฏๅฏนๅบ”ๅธƒๅฑ€ๆ–‡ไปถไธญView็š„ id;

    ไธ€ใ€้‡‡็”จๆ™ฎ้€šๆ–นๅผๅฐ่ฃ…็š„ๅŸบ็ก€ๆ–‡ไปถไป‹็ป

    1ใ€BaseActivity

    package:cn.onestravel.library.kotlin.base.activity

    ๆ‰€ๆœ‰Activity็š„ๅŸบ็ฑป๏ผŒๅฎšไน‰ไธ€ไบ›ๅญ็ฑปๅฟ…้กปๅฎž็Žฐ็š„ๅ’Œๅฏๅฎž็Žฐ็š„ๆ–นๆณ•๏ผš

     /**
         * ่Žทๅ–ๅธƒๅฑ€ID,ๅญ็ฑปๅฟ…้กปๅฎž็Žฐ
         */
        protected abstract fun getLayoutId(): Int
    
    
        /**
         * ๅˆๅง‹ๅŒ– View ็š„็›ธๅ…ณๆ“ไฝœ๏ผŒ่‹ฅๆœ‰้œ€่ฆๅฏๅœจๅญ็ฑปๅฎž็Žฐ
         */
        protected open fun initView() {}
    
        /**
         * ๅˆๅง‹ๅŒ– Listener ไบ‹ไปถ็š„็›ธๅ…ณๆ“ไฝœ๏ผŒ่‹ฅๆœ‰้œ€่ฆๅฏๅœจๅญ็ฑปๅฎž็Žฐ
         */
        protected open fun initListener() {}
    
    
        /**
         * ๅˆๅง‹ๅŒ– Data ๆ•ฐๆฎ็š„็›ธๅ…ณๆ“ไฝœ๏ผŒ่‹ฅๆœ‰้œ€่ฆๅฏๅœจๅญ็ฑปๅฎž็Žฐ
         */
        protected open fun initData() {}
    
    
        /**
         * ๅœจไธป็บฟ็จ‹ๅผนๅ‡บToast ๆ็คบ
         * @param msg ้œ€่ฆๅผนๅ‡บ็š„ๆ็คบไฟกๆฏ
         */
        protected open fun showToast(msg:String){
            runOnUiThread {
                toast(msg)
            }
        }
    
        /**
         * ๅœจไธป็บฟ็จ‹ๅผนๅ‡บToast ๆ็คบ
         * @param stringRes ้œ€่ฆๅผนๅ‡บ็š„ๆ็คบไฟกๆฏ็š„string่ต„ๆบID
         */
        protected open fun showToast(stringRes:Int){
            runOnUiThread {
                toast(getString(stringRes))
            }
        }
    
        /**
         * ่ทณ่ฝฌๅˆฐๅฆไธ€ไธชActivity๏ผŒๅนถไธ”finish ๆމๅฝ“ๅ‰Activity
         * ้œ€่ฆ่ทณ่ฝฌ็š„Activityๅฟ…้กป็ปงๆ‰ฟไบŽBaseActivity ๆˆ–่€…
         * @param params ๅฏๅ˜ๅ‚ๆ•ฐ๏ผŒ้œ€่ฆ้€š่ฟ‡intentไผ ้€’็š„ๅ‚ๆ•ฐ eg:"key" to "value"
         */
        inline fun <reified T: BaseActivity> startActivityAndFinish(vararg params: Pair<String, Any?>) {
            startActivity<T>(*params)
            finish()
        }

    2ใ€BaseListActivity

    package:cn.onestravel.library.kotlin.base.activity

    ็ปงๆ‰ฟ่‡ชBaseActivity๏ผŒๅฎž็Žฐ้’ˆๅฏนRecyclerViewๅฎž็Žฐๅˆ—่กจๆ•ฐๆฎ็š„ไธ€ไบ›้…็ฝฎ๏ผŒ็ฎ€ๅŒ–ๅฎž็Žฐๅชๆœ‰ไธ€ไธชๅˆ—่กจๅธƒๅฑ€็š„Activity๏ผŒๅนถไธ”ๅฎž็ŽฐไธŠๆ‹‰ๅŠ ่ฝฝ๏ผŒไธ‹ๆ‹‰ๅˆทๆ–ฐๆ“ไฝœใ€‚

    ไธป่ฆๆ–นๆณ•ๅฆ‚ไธ‹๏ผš

     protected fun getRecyclerView():LoadMoreRecyclerView{
            return mRecyclerView
        }
    
        /**
         * ่Žทๅ–recyclerView็š„ๅธƒๅฑ€็ฎก็†ๅ™จ๏ผŒๅญ็ฑปๅฏ้‡ๅ†™่ฏฅๆ–นๆณ•๏ผŒๆฅๆ›ดๆ”นๅธƒๅฑ€็ฎก็†ๅ™จ
         */
        protected open fun getLayoutManager(): RecyclerView.LayoutManager {
            val layoutManager: LinearLayoutManager = LinearLayoutManager(this)
            //่ฎพ็ฝฎไธบๅž‚็›ดๅธƒๅฑ€๏ผŒ่ฟ™ไนŸๆ˜ฏ้ป˜่ฎค็š„
            layoutManager.orientation = OrientationHelper.VERTICAL
            return layoutManager
        }
    
    
        /**
         * ่ฎพ็ฝฎRecyclerView ็š„Adapter้€‚้…ๅ™จ
         * @param adapter ่ฎพ็ฝฎ็š„Adapter๏ผŒๅฟ…้กปๆ˜ฏBaseRecyclerAdapter็š„ๅญ็ฑป
         */
        protected fun <T> setAdapter(adapter: BaseRecyclerAdapter<T>) {
            mRecyclerView.adapter = adapter
        }
    
        /**
         * ่ฎพ็ฝฎๅˆทๆ–ฐๆŽงไปถ็š„้ขœ่‰ฒ
         */
        protected fun setRefreshColorSchemeColors(@ColorInt vararg colors: Int) {
            mRefreshLayout.setColorSchemeColors(*colors)
        }
        /**
         * ่ฎพ็ฝฎๅˆทๆ–ฐๆŽงไปถ็š„้ขœ่‰ฒ
         */
        protected fun setColorSchemeResources(@ColorRes vararg colorIds: Int) {
            mRefreshLayout.setColorSchemeResources(*colorIds)
        }
    
        /**
         * ่ฎพ็ฝฎๅˆทๆ–ฐๆŽงไปถๆ˜ฏๅฆๆ˜พ็คบ
         */
        protected fun isRefresh(isRefresh: Boolean) {
            mRefreshLayout.isRefreshing = false
        }
    
        /**
         * ๅˆทๆ–ฐๅฎŒๆˆ
         */
        protected fun refreshComplete() {
            mRefreshLayout.isRefreshing = false
        }
    
        /**
         * ๅˆทๆ–ฐๆ•ฐๆฎ๏ผŒๅญ็ฑปๅฎž็Žฐ่ฏฅๆ–นๆณ•๏ผŒ่ฟ›่กŒๆ•ฐๆฎ่ฏทๆฑ‚
         */
        protected open fun refreshDatas() {
    
        }
    
        /**
         * ๅŠ ่ฝฝๆ›ดๅคšๅฎŒๆˆ
         */
        protected fun loadMoreComplete() {
            mRecyclerView.loadMoreComplete(true)
        }
    
        /**
         * ่ฎพ็ฝฎๆ˜ฏๅฆๅฏไปฅๅŠ ่ฝฝๆ›ดๅคš
         */
        protected fun canLoadMore(canLoadMore: Boolean) {
            mRecyclerView.loadMoreEnable = canLoadMore
        }
    
        /**
         * ่ฎพ็ฝฎๆ˜ฏๅฆ่ฟ˜ๆœ‰ๆ›ดๅคš็š„ๆ•ฐๆฎ
         */
        protected fun hasLoadMore(hasLoadMore: Boolean) {
            mRecyclerView.hasMore = hasLoadMore
        }
    
        /**
         * ๅŠ ่ฝฝๆ–ฐๆ•ฐๆฎ๏ผŒๅญ็ฑปๅฎž็Žฐ่ฏฅๆ–นๆณ•๏ผŒ่ฟ›่กŒๆ•ฐๆฎ่ฏทๆฑ‚
         */
        protected open fun loadMoreDatas() {
    
        }

    3ใ€BaseRecyclerAdapter

    package:cn.onestravel.library.kotlin.base.adapter

    ้’ˆๅฏนRecyclerViewไฝฟ็”จ็š„RecyclerView.Adapter่ฟ›่กŒๅฐ่ฃ…๏ผŒๅฎž็Žฐไธ€ไบ›ๅŸบ็ก€็š„ๅธƒๅฑ€๏ผˆไธๅธธๅ˜ๅŒ–็š„๏ผ‰่ฎพ็ฝฎ็š„ๆ–นๆณ•๏ผŒๅฎšไน‰ไธ€ไบ›ๆ–นๆณ•๏ผŒ็ฎ€ๅŒ–ๅญ็ฑป็š„ๅฎž็Žฐ๏ผŒๆ›ดๅŠ ๆœ‰ๅˆฉไบŽ็ผฉ็Ÿญๅผ€ๅ‘ๆ—ถ้—ด๏ผ›ๅฎž็Žฐadapterไธญๆ็คบToast็š„ๆ–นๆณ•๏ผŒไปฅๅŠๆทปๅŠ ใ€่ฎพ็ฝฎๆ•ฐๆฎ๏ผŒๆˆ–่€…ๅŸบ็ก€View็š„่ฎพ็ฝฎ็›ธๅ…ณๅ†…ๅฎน็š„ๆ–นๆณ•๏ผ›ๅฏนItem็‚นๅ‡ปๅ’Œ้•ฟๆŒ‰็š„็›‘ๅฌไบ‹ไปถใ€‚

    ไธป่ฆๆ–นๆณ•ๅฆ‚ไธ‹๏ผš

    abstract class BaseRecyclerAdapter<T> : RecyclerView.Adapter<VH>(), View.OnClickListener, View.OnLongClickListener {
        private val mDatas: MutableList<T> = ArrayList<T>()
        private lateinit var context: Context
        private var clickListener: OnItemClickListener<T>? = null
        private var longClickListener: OnItemLongClickListener<T>? = null
    
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
            context = parent.context
            val convertView = LayoutInflater.from(parent.context).inflate(getLayoutId(viewType), parent, false)
            convertView.setOnClickListener(this)
            convertView.setOnLongClickListener(this)
            return VH(convertView)
        }
    
        /**
         * ่ฎพ็ฝฎItem ็š„็‚นๅ‡ปไบ‹ไปถ
         */
        fun setOnItemClick(listener: OnItemClickListener<T>) {
            clickListener = listener
        }
    
        /**
         * ่ฎพ็ฝฎItem ็š„็‚นๅ‡ปไบ‹ไปถ
         */
        fun setOnItemClick(onClick: (view:View,position:Int,data:T) -> Unit) {
            clickListener = object :  OnItemClickListener<T> {
                override fun onItemClick(view: View, position: Int, data: T) {
                    onClick(view,position,data)
                }
            }
        }
    
        /**
         * ่ฎพ็ฝฎItem ็š„้•ฟๆŒ‰ไบ‹ไปถ
         */
        fun setOnItemLongClick(listener:OnItemLongClickListener<T>) {
            longClickListener = listener
        }
    
        /**
         * ่ฎพ็ฝฎItem ็š„้•ฟๆŒ‰ไบ‹ไปถ
         */
        fun setOnItemLongClick(onLongClick: (view:View,position:Int,data:T) -> Boolean) {
            longClickListener = object : OnItemLongClickListener<T> {
                override fun onItemLongClick(view: View, position: Int, data: T):Boolean {
                    return onLongClick(view,position,data)
                }
            }
        }
    
        override fun onClick(p0: View?) {
            val position:Int = p0?.getTag(R.id.itemViewPosition) as Int
            val data:T = mDatas.get(position)
            clickListener?.onItemClick(p0,position,data)
        }
    
        override fun onLongClick(p0: View?): Boolean {
            val position:Int = p0?.getTag(R.id.itemViewPosition) as Int
            val data:T = mDatas.get(position)
            return longClickListener?.onItemLongClick(p0,position,data) ?: true
        }
    
        /**
         * ่ฎพ็ฝฎๆ•ฐๆฎ,ๅนถไธ”ไผšๆธ…็ฉบๅŽŸๆ•ฐๆฎๅˆ—่กจ
         * @param datas ๆ–ฐ็š„ๆ•ฐๆฎๅˆ—่กจ
         */
        open fun setDatas(datas: List<T>) {
            mDatas.clear()
            mDatas.addAll(datas)
            notifyDataSetChanged()
        }
    
        /**
         * ๆทปๅŠ ๆ–ฐ็š„ๆ•ฐๆฎๅˆ—่กจๅˆฐๅŽŸๆ•ฐๆฎๅˆ—่กจๆœซๅฐพ
         * @param datas ๆ–ฐ็š„ๆ•ฐๆฎๅˆ—่กจ
         */
        open fun addDatas(datas: List<T>) {
            mDatas.addAll(datas)
            notifyDataSetChanged()
        }
    
        /**
         * ๆทปๅŠ ๆ–ฐ็š„ๆ•ฐๆฎๅˆ—่กจๅˆฐๅŽŸๆ•ฐๆฎๅˆ—่กจ็š„ๆŒ‡ๅฎšไฝ็ฝฎ
         * @param position ้œ€่ฆๆทปๅŠ ็š„ๆŒ‡ๅฎšไฝ็ฝฎ
         * @param datas ๆ–ฐ็š„ๆ•ฐๆฎๅˆ—่กจ
         */
        open fun addDatas(position: Int, datas: List<T>) {
            val pos = if (position > mDatas.size) {
                mDatas.size
            } else position
            mDatas.addAll(pos, datas)
            notifyDataSetChanged()
        }
    
        /**
         * ๆ›ดๆ–ฐๆ•ฐๆฎๅˆ—่กจๆŒ‡ๅฎšไฝ็ฝฎไธŠ็š„ๆ•ฐๆฎ
         * @param position ้œ€่ฆๆ›ดๆ–ฐๆ•ฐๆฎ็š„ไฝ็ฝฎ
         * @param data ๆ›ดๆ–ฐๅŽ็š„ๆ•ฐๆฎ
         */
        open fun updateData(position: Int, data: T) {
            if (position < mDatas.size) {
                mDatas.removeAt(position)
                mDatas.add(position, data)
                notifyItemChanged(position)
            }
        }
    
        /**
         * ๆทปๅŠ ๆ–ฐ็š„ๆ•ฐๆฎๅˆฐๅŽŸๆ•ฐๆฎๅˆ—่กจๆœซๅฐพ
         * @param datas ๆ–ฐ็š„ๆ•ฐๆฎ
         */
        open fun addData(data: T) {
            mDatas.add(data)
            notifyItemInserted(mDatas.size - 1)
        }
    
        /**
         * ๆทปๅŠ ๆ–ฐ็š„ๆ•ฐๆฎๅˆฐๅŽŸๆ•ฐๆฎๅˆ—่กจ็š„ๆŒ‡ๅฎšไฝ็ฝฎ
         * @param position ้œ€่ฆๆทปๅŠ ็š„ๆŒ‡ๅฎšไฝ็ฝฎ
         * @param data ๆ–ฐ็š„ๆ•ฐๆฎ
         */
        open fun addData(position: Int, data: T) {
            val pos = if (position > mDatas.size) {
                mDatas.size
            } else position
            mDatas.add(pos, data)
            notifyItemInserted(pos)
        }
    
        /**
         * ็งป้™คๆŒ‡ๅฎšไฝ็ฝฎไธŠ็š„ๆ•ฐๆฎ
         * @param position ้œ€่ฆๆทปๅŠ ็š„ๆŒ‡ๅฎšไฝ็ฝฎ
         */
        open fun removeDataAt(position: Int) {
            if (position < mDatas.size) {
                mDatas.removeAt(position)
                notifyItemRemoved(position)
            }
        }
    
        protected open fun showToast(msg: String) {
            context.runOnUiThread {
                context.toast(msg)
            }
        }
    
        /**
         * ็งป้™คๆŒ‡ๅฎš็š„ๆ•ฐๆฎ
         * @param data ้œ€่ฆ็งป้™ค็š„ๆ•ฐๆฎๅฎžไฝ“
         */
        open fun removeData(data: T) {
            if (mDatas.contains(data)) {
                val position = mDatas.indexOf(data)
                mDatas.removeAt(position)
                notifyItemRemoved(position)
            }
        }
    
        /**
         * ๆ นๆฎView็š„็ฑปๅž‹่Žทๅ–ๅฏนๅบ”็š„Itemๅธƒๅฑ€็š„ID
         */
        @LayoutRes
        abstract fun getLayoutId(viewType: Int): Int
    
    
        /**
         * ็ป‘ๅฎšViewHolder ๆ—ถๆ‰ง่กŒ็š„ๆ–นๆณ•๏ผŒๅœจๆญคๆ–นๆณ•้‡Œๅค„็†ๅฏนItem็š„view็š„ๆ“ไฝœ
         */
        abstract fun onBindVH(holder: VH, position: Int, datas: T)
    
        /**
         * ่ฟ”ๅ›žๆ•ฐๆฎ็š„ๆ•ฐ้‡
         */
        override fun getItemCount(): Int {
            return mDatas.size
        }
    
        override fun onBindViewHolder(holder: VH, position: Int) {
            holder.itemView.setTag(R.id.itemViewPosition, position)
            onBindVH(holder, position, mDatas.get(position))
        }
    
    
    }
    
    /**
     *Item ็š„็‚นๅ‡ปไบ‹ไปถ
     */
    interface OnItemClickListener<T> {
        fun onItemClick(view: View, position: Int, data: T)
    }
    
    /**
     *Item ็š„้•ฟๆŒ‰ไบ‹ไปถ
     */
    interface OnItemLongClickListener<T> {
        fun onItemLongClick(view: View, position: Int, data: T):Boolean
    }
    
    /**
     * ๆ‰€ๆœ‰็š„Adapter ไฝฟ็”จ็š„ViewHolder
     */
    class VH(itemView: View) : RecyclerView.ViewHolder(itemView) {
    
    
        /**
         * ๆ นๆฎView็š„id่Žทๅ–ๅฏนๅบ”็š„View
         */
        inline fun <reified E : View> getView(@IdRes viewId: Int): E {
            return itemView.find<E>(viewId)
        }
    
        /**
         * ๅฏนTextViewๅŠๅ…ถๅญ็ฑป่ฎพ็ฝฎๆ–‡ๆœฌๅ†…ๅฎน
         * @param viewId ๅฏนๅบ”็š„View ็š„id
         * @param value ้œ€่ฆ่ฎพ็ฝฎ็š„ๆ–‡ๆœฌๅ†…ๅฎน
         */
        inline fun setText(@IdRes viewId: Int, value: String) {
            val view: View = this.getView(viewId)
            if (view is TextView) {
                val tv: TextView = view
                tv.text = value
            }
        }
    
        /**
         * ๅฏนTextViewๅŠๅ…ถๅญ็ฑป่ฎพ็ฝฎๆ–‡ๆœฌๅ†…ๅฎน
         * @param viewId ๅฏนๅบ”็š„View ็š„id
         * @param value ้œ€่ฆ่ฎพ็ฝฎ็š„ๆ–‡ๆœฌๅ†…ๅฎน
         */
        inline fun setText(@IdRes viewId: Int, value: Spannable) {
            val view: View = this.getView(viewId)
            if (view is TextView) {
                val tv: TextView = view
                tv.text = value
            }
        }
    
        /**
         * ๅฏนTextViewๅŠๅ…ถๅญ็ฑป่ฎพ็ฝฎๆ–‡ๆœฌๅ†…ๅฎน
         * @param viewId ๅฏนๅบ”็š„View ็š„id
         * @param stringRes ้œ€่ฆ่ฎพ็ฝฎ็š„ๆ–‡ๆœฌ่ต„ๆบ็š„id
         */
        inline fun setText(@IdRes viewId: Int, @StringRes stringRes: Int) {
            val view: View = this.getView(viewId)
            if (view is TextView) {
                val tv: TextView = view
                tv.setText(stringRes)
            }
        }
    
        /**
         * ๅฏนImageViewๅŠๅ…ถๅญ็ฑป่ฎพ็ฝฎๅ›พ็‰‡
         * @param viewId ๅฏนๅบ”็š„View ็š„id
         * @param resId ้œ€่ฆ่ฎพ็ฝฎ็š„ๅ›พ็‰‡่ต„ๆบ็š„id
         */
        inline fun setImageResource(@IdRes viewId: Int, @DrawableRes resId: Int) {
            val view: View = getView(viewId)
            if (view is ImageView) {
                val iv: ImageView = view
                iv.imageResource = resId
            }
        }
    
        /**
         * ๅฏนImageViewๅŠๅ…ถๅญ็ฑป่ฎพ็ฝฎๅ›พ็‰‡
         * @param viewId ๅฏนๅบ”็š„View ็š„id
         * @param imgUrl ้œ€่ฆ่ฎพ็ฝฎ็š„็ฝ‘็ปœๅ›พ็‰‡็š„ๅœฐๅ€
         */
        inline fun setImageUrl(@IdRes viewId: Int, imgUrl: String) {
            val view: View = getView(viewId)
            if (view is ImageView) {
                val iv: ImageView = view
                iv.loadImage(imgUrl)
            }
        }
    
        /**
         * ๅฏนViewๅŠๅ…ถๅญ็ฑป่ฎพ็ฝฎ่ƒŒๆ™ฏๅ›พ็‰‡
         * @param viewId ๅฏนๅบ”็š„View ็š„id
         * @param resId ้œ€่ฆ่ฎพ็ฝฎ็š„่ƒŒๆ™ฏๅ›พ็‰‡็š„่ต„ๆบๅœฐๅ€
         */
        inline fun setBackgroundResource(@IdRes viewId: Int, @DrawableRes resId: Int) {
            val view: View = getView(viewId)
            view.setBackgroundResource(resId)
        }
    
        /**
         * ๅฏนViewๅŠๅ…ถๅญ็ฑป่ฎพ็ฝฎ่ƒŒๆ™ฏ้ขœ่‰ฒ
         * @param viewId ๅฏนๅบ”็š„View ็š„id
         * @param color ้œ€่ฆ่ฎพ็ฝฎ็š„่ƒŒๆ™ฏ้ขœ่‰ฒ
         */
        inline fun setBackgroundColor(@IdRes viewId: Int, @ColorInt color: Int) {
            val view: View = getView(viewId)
            view.setBackgroundColor(color)
        }
    
    
        /**
         * ๅฏนViewๅŠๅ…ถๅญ็ฑป่ฎพ็ฝฎ็‚นๅ‡ปไบ‹ไปถ
         * @param viewId ๅฏนๅบ”็š„View ็š„id
         * @param color ้œ€่ฆ่ฎพ็ฝฎ็š„่ƒŒๆ™ฏ้ขœ่‰ฒ
         */
        inline fun setOnClick(@IdRes viewId: Int, crossinline onClick: (View) -> Unit) {
            val view: View = getView(viewId)
            view.setOnClickListener {
                onClick.invoke(it)
            }
        }
    
    }

    4ใ€ImageViewExtend

    package: cn.onestravel.library.kotlin.base.extend

    ๆ”นๆ–‡ไปถๆ˜ฏImageView็š„ๆ‰ฉๅฑ•ๆ–นๆณ•็š„ๆ–‡ไปถ๏ผŒไธป่ฆ้’ˆๅฏนImageViewๅŠ ่ฝฝ็ฝ‘็ปœๅ›พ็‰‡่€Œๆ–ฐๅขž็š„ไธ€ไบ›ๆ‰ฉๅฑ•ๆ–นๆณ•

    ๅ…ทไฝ“ๆ–นๆณ•ๅฆ‚ไธ‹๏ผš

    inline fun ImageView.loadImage(imgUrl: String): ImageView {
        ImageUtils.loadImageUrl(this.context, imgUrl, this)
        return this
    }
    
    inline fun ImageView.loadBitmap(imgUrl: String): ImageView {
        ImageUtils.loadImageBitmap(this.context, imgUrl, this)
        return this
    }
    
    inline fun ImageView.loadGif(imgUrl: String): ImageView {
        ImageUtils.loadImageGif(this.context, imgUrl, this)
        return this
    }
    
    inline fun ImageView.loadImgCallBack(imgUrl: String, requestListener: RequestListener<Bitmap>): ImageView {
        ImageUtils.loadImageCallBack(this.context, imgUrl, this, requestListener)
        return this
    }
    

    5ใ€BaseFragment

    package: cn.onestravel.library.kotlin.base.fragment

    ๆ‰€ๆœ‰Fragment็š„ๅŸบ็ฑป๏ผŒๅฎšไน‰ไธ€ไบ›ๅญ็ฑปๅฟ…้กปๅฎž็Žฐ็š„ๅ’Œๅฏๅฎž็Žฐ็š„ๆ–นๆณ•๏ผŒๅ…ทไฝ“ๆ–นๆณ•ไธŽBaseActivityๆ–นๆณ•็ฑปไผผใ€‚

    6ใ€BaseListFragment

    package: cn.onestravel.library.kotlin.base.fragment

    ็ปงๆ‰ฟ่‡ชBaseFragment๏ผŒๅฎž็Žฐ้’ˆๅฏนRecyclerViewๅฎž็Žฐๅˆ—่กจๆ•ฐๆฎ็š„ไธ€ไบ›้…็ฝฎ๏ผŒ็ฎ€ๅŒ–ๅฎž็Žฐๅชๆœ‰ไธ€ไธชๅˆ—่กจๅธƒๅฑ€็š„Fragment๏ผŒๅนถไธ”ๅฎž็ŽฐไธŠๆ‹‰ๅŠ ่ฝฝ๏ผŒไธ‹ๆ‹‰ๅˆทๆ–ฐๆ“ไฝœ๏ผ›ๅ…ทไฝ“ๆ–นๆณ•ไธŽBaseListActivity็›ธๅŒใ€‚

    7ใ€DensityUtil

    package: cn.onestravel.library.kotlin.base.utils

    ๅฐบๅฏธ่ฝฌๆขๅทฅๅ…ท็ฑป๏ผŒๅฏไปฅๅฐ†dip่ฝฌไธบpx๏ผŒๅฐ†px่ฝฌไธบdip๏ผ›่Žทๅ–ๅฑๅน•ๅฎฝๅบฆๅ’Œ้ซ˜ๅบฆใ€‚

    	/**
         * dip่ฝฌๆขไธบpx
         */
        fun dip2px(dp: Int): Int {
            return (dp * density).toInt()
        }
    
    
        /**
         * px่ฝฌๆขไธบdip
         */
        fun px2dip(px:  Float): Int {
            return (px / density).toInt()
        }
    
        /**
         * ่Žทๅ–ๅฑๅน•ๅฎฝๅบฆ
         */
        fun appWidth(): Int {
            return Resources.getSystem().getDisplayMetrics().widthPixels
        }
    
        /**
         * ่Žทๅ–ๅฑๅน•้ซ˜ๅบฆ
         */
        fun appHeight(): Int {
            return Resources.getSystem().getDisplayMetrics().heightPixels
        }

    8ใ€CircleTextView

    package๏ผšcn.onestravel.library.kotlin.base.view

    ่‡ชๅฎšไน‰ๅœ†ๅฝขTextView๏ผŒไธ€ๆปก่ถณไธๅŒ้œ€ๆฑ‚

    9ใ€EmptyView

    package๏ผšcn.onestravel.library.kotlin.base.view

    ่‡ชๅฎšไน‰ ๆ•ฐๆฎไธบ็ฉบ็š„้กต้ข่ง†ๅ›พ๏ผŒไธป่ฆๆœ‰ไธ‰ไธชๅŠŸ่ƒฝ็ฑปๅž‹๏ผŒๅˆ†ๅˆซไธบ๏ผšๆ•ฐๆฎไธบ็ฉบๆ˜พ็คบ้กต้ข๏ผˆTYPE_EMPTY๏ผ‰๏ผ›ๅŠ ่ฝฝ่ฟ›ๅบฆๆ็คบ้กต้ข๏ผˆTYPE_LOADING๏ผ‰๏ผ›ๅŠ ่ฝฝๅคฑ่ดฅๅฏ็‚นๅ‡ป้‡่ฏ•้กต้ข๏ผˆTYPE_RELOAD๏ผ‰

    ้‡ๆ–ฐๅฎšไน‰็š„ไธ€ไธ‹ๆ–นๆณ•ๅฆ‚ไธ‹๏ผš

    /**
         * ่ฎพ็ฝฎ้กต้ขๆ˜พ็คบ็ฑปๅž‹
         *
         * @param type
         */
        fun setEmptyType(type: Int) {
            _setEmptyType(type, true)
        }
    
        /**
         * ่ฎพ็ฝฎ้กต้ขๆ˜พ็คบ็ฑปๅž‹
         *
         * @param type
         */
        private fun _setEmptyType(type: Int, isShow: Boolean) {
            this.emptyType = type
            when (type) {
                TYPE_EMPTY -> {
                    layoutLoading!!.visibility = View.GONE
                    layoutReload!!.visibility = View.GONE
                    layoutEmpty!!.visibility = View.VISIBLE
                    btnReload!!.visibility = View.GONE
                    ivEmptyImg!!.visibility = View.VISIBLE
                }
                TYPE_LOADING -> {
                    layoutLoading!!.visibility = View.VISIBLE
                    layoutEmpty!!.visibility = View.GONE
                    layoutReload!!.visibility = View.GONE
                    if (tvLoadingMsg != null) {
                        tvLoadingMsg!!.text = "ๆญฃๅœจๅŠ ่ฝฝ..."
                    }
                }
                TYPE_RELOAD -> {
                    layoutLoading!!.visibility = View.GONE
                    layoutEmpty!!.visibility = View.GONE
                    layoutReload!!.visibility = View.VISIBLE
                    btnReload!!.visibility = View.VISIBLE
                    ivEmptyImg!!.visibility = View.VISIBLE
                }
            }
            if (isShow) {
                show()
            }
        }
    
        /**
         * ่ฎพ็ฝฎ็ฉบๆ•ฐๆฎ็•Œ้ข็š„่ƒŒๆ™ฏ่‰ฒ
         *
         * @param color ่ƒŒๆ™ฏ่‰ฒ
         */
        fun setEmptyBackgroundColor(color: Int) {
            layoutEmpty!!.setBackgroundColor(color)
        }
    
        /**
         * ่ฎพ็ฝฎ้”™่ฏฏๆ่ฟฐ
         *
         * @param resId
         */
        fun setEmptyText(@StringRes resId: Int) {
            if (tvEmptyMsg != null) {
                tvEmptyMsg!!.text = mContext!!.getString(resId)
            }
        }
    
        /**
         * ่ฎพ็ฝฎ้”™่ฏฏๆ่ฟฐ
         *
         * @param text
         */
        fun setEmptyText(text: CharSequence?) {
            var text = text
            if (text == null) {
                text = ""
            }
            if (tvEmptyMsg != null) {
                tvEmptyMsg!!.text = text
            }
        }
    
    
        /**
         * ่ฎพ็ฝฎ้”™่ฏฏๆ่ฟฐๅญ—ไฝ“ๅคงๅฐ
         *
         * @param size
         */
        fun setEmptyTextSize(size: Float) {
            if (tvEmptyMsg != null) {
                tvEmptyMsg!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, size)
            }
        }
    
        /**
         * ่ฎพ็ฝฎ้”™่ฏฏๆ่ฟฐ้ขœ่‰ฒ
         *
         * @param color
         */
        fun setEmptyTextColor(color: Int) {
            if (tvEmptyMsg != null) {
                tvEmptyMsg!!.setTextColor(color)
            }
        }
    
        /**
         * ่ฎพ็ฝฎ้”™่ฏฏๆ่ฟฐ้ขœ่‰ฒ
         *
         * @param colors
         */
        fun setEmptyTextColor(colors: ColorStateList) {
            if (tvEmptyMsg != null) {
                tvEmptyMsg!!.setTextColor(colors)
            }
        }
    
        /**
         * ่ฎพ็ฝฎ้กต้ขๅ›พ็‰‡
         *
         * @param resId
         */
        fun setEmptyImgResource(@DrawableRes resId: Int) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                this.noDataImg = mContext!!.getDrawable(resId)
            } else {
                this.noDataImg = mContext!!.resources.getDrawable(resId)
            }
            if (ivEmptyImg != null) {
                ivEmptyImg!!.setImageResource(resId)
            }
        }
    
    
        /**
         * ่ฎพ็ฝฎ้กต้ขๅ›พ็‰‡
         *
         * @param noDataImg
         */
        fun setEmptyImg(noDataImg: Drawable) {
            this.noDataImg = noDataImg
            if (ivEmptyImg != null) {
                ivEmptyImg!!.setImageDrawable(noDataImg)
            }
        }
    
        /**
         * ่Žทๅ–ๅŠ ่ฝฝๆŒ‰้’ฎๆ–‡ๅญ—
         */
        fun getReloadBtnText(): String? {
            return reloadBtnText
        }
    
        /**
         * ่ฎพ็ฝฎ้‡ๆ–ฐๅŠ ่ฝฝๆŒ‰้’ฎๆ–‡ๅญ—
         *
         * @param resId
         */
        fun setReloadBtnText(resId: Int) {
            this.reloadBtnText = mContext!!.getString(resId)
            if (btnReload != null) {
                btnReload!!.text = this.reloadBtnText
            }
        }
    
        /**
         * ่ฎพ็ฝฎ้‡ๆ–ฐๅŠ ่ฝฝๆŒ‰้’ฎๆ–‡ๅญ—
         *
         * @param reloadBtnText
         */
        fun setReloadBtnText(reloadBtnText: String) {
            this.reloadBtnText = reloadBtnText
            if (btnReload != null) {
                btnReload!!.text = this.reloadBtnText
            }
        }
    
    
        /**
         * ่ฎพ็ฝฎ้‡ๆ–ฐๅŠ ่ฝฝๆŒ‰้’ฎๆ–‡ๅญ—ๅคงๅฐ
         *
         * @param reloadBtnTextSize
         */
        fun setReloadBtnTextSize(reloadBtnTextSize: Float) {
            this.reloadBtnTextSize = reloadBtnTextSize
            if (btnReload != null) {
                btnReload!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, this.reloadBtnTextSize)
            }
        }
    
    
        /**
         * ่ฎพ็ฝฎ้‡ๆ–ฐๅŠ ่ฝฝๆŒ‰้’ฎๆ–‡ๅญ—้ขœ่‰ฒ
         *
         * @param color
         */
        fun setReloadBtnTextColor(color: Int) {
            this.reloadBtnTextColor = color
            if (btnReload != null) {
                btnReload!!.setTextColor(this.reloadBtnTextColor)
            }
        }
    
        /**
         * ่ฎพ็ฝฎ้‡ๆ–ฐๅŠ ่ฝฝๆŒ‰้’ฎๆ–‡ๅญ—้ขœ่‰ฒ
         *
         * @param colors
         */
        fun setReloadBtnTextColor(colors: ColorStateList) {
            if (btnReload != null) {
                btnReload!!.setTextColor(colors)
            }
        }
    
    
        /**
         * ่ฎพ็ฝฎๅŠ ่ฝฝๆŒ‰้’ฎ่ƒŒๆ™ฏ
         *
         * @param reloadBackground
         */
        fun setReloadBtnBackground(reloadBackground: Drawable) {
            this.reloadBtnBackground = reloadBackground
            if (btnReload != null) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    btnReload!!.background = this.reloadBtnBackground
                } else {
                    btnReload!!.setBackgroundDrawable(this.reloadBtnBackground)
                }
            }
        }
    
        /**
         * ่ฎพ็ฝฎๅŠ ่ฝฝๆŒ‰้’ฎ่ƒŒๆ™ฏ
         *
         * @param color
         */
        fun setReloadBtnBackgroundColor(color: Int) {
            this.reloadBtnBackground = ColorDrawable(color)
            if (btnReload != null) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    btnReload!!.background = this.reloadBtnBackground
                } else {
                    btnReload!!.setBackgroundDrawable(this.reloadBtnBackground)
                }
            }
        }
    
        /**
         * ่ฎพ็ฝฎๅŠ ่ฝฝๆŒ‰้’ฎ่ƒŒๆ™ฏ
         *
         * @param resId
         */
        fun setReloadBtnBackgroundResource(resId: Int) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                this.reloadBtnBackground = mContext!!.getDrawable(resId)
            } else {
                this.reloadBtnBackground = mContext!!.resources.getDrawable(resId)
            }
            if (btnReload != null) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    btnReload!!.background = this.reloadBtnBackground
                } else {
                    btnReload!!.setBackgroundDrawable(this.reloadBtnBackground)
                }
            }
        }
    
        /**
         * ่Žทๅ–ๅŠ ่ฝฝๆ็คบๆ–‡ๅญ—
         */
        fun getReloadText(): String? {
            return reloadText
        }
    
        /**
         * ่ฎพ็ฝฎ้‡ๆ–ฐๅŠ ่ฝฝๆ็คบๆ–‡ๅญ—
         *
         * @param resId
         */
        fun setReloadText(resId: Int) {
            this.reloadText = mContext!!.getString(resId)
            if (tvReloadMsg != null) {
                tvReloadMsg!!.text = this.reloadText
            }
        }
    
        /**
         * ่ฎพ็ฝฎ้‡ๆ–ฐๅŠ ่ฝฝๆ็คบๆ–‡ๅญ—
         *
         * @param reloadText
         */
        fun setReloadText(reloadText: String) {
            this.reloadText = reloadText
            if (tvReloadMsg != null) {
                tvReloadMsg!!.text = this.reloadText
            }
        }
    
    
        /**
         * ่ฎพ็ฝฎ้‡ๆ–ฐๅŠ ่ฝฝๆ็คบๆ–‡ๅญ—ๅคงๅฐ
         *
         * @param reloadTextSize
         */
        fun setReloadTextSize(reloadTextSize: Float) {
            this.reloadTextSize = reloadTextSize
            if (tvReloadMsg != null) {
                tvReloadMsg!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, this.reloadTextSize)
            }
        }
    
    
        /**
         * ่ฎพ็ฝฎ้‡ๆ–ฐๅŠ ่ฝฝๆ็คบๆ–‡ๅญ—้ขœ่‰ฒ
         *
         * @param color
         */
        fun setReloadTextColor(color: Int) {
            this.reloadTextColor = color
            if (tvReloadMsg != null) {
                tvReloadMsg!!.setTextColor(this.reloadTextColor)
            }
        }
    
        /**
         * ่ฎพ็ฝฎ้‡ๆ–ฐๅŠ ่ฝฝๆ็คบๆ–‡ๅญ—้ขœ่‰ฒ
         *
         * @param colors
         */
        fun setReloadTextColor(colors: ColorStateList) {
            if (tvReloadMsg != null) {
                tvReloadMsg!!.setTextColor(colors)
            }
        }
    
        /**
         * ่ฎพ็ฝฎ้กต้ขๅ›พ็‰‡
         *
         * @param resId
         */
        fun setReloadImgResource(@DrawableRes resId: Int) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                this.reloadImage = mContext!!.getDrawable(resId)
            } else {
                this.reloadImage = mContext!!.resources.getDrawable(resId)
            }
            if (ivReloadImg != null) {
                ivReloadImg!!.setImageResource(resId)
            }
        }
    
    
        /**
         * ่ฎพ็ฝฎ้กต้ขๅ›พ็‰‡
         *
         * @param reloadImage
         */
        fun setReloadImg(reloadImage: Drawable) {
            this.reloadImage = reloadImage
            if (ivReloadImg != null) {
                ivReloadImg!!.setImageDrawable(reloadImage)
            }
        }
    
    
        /**
         * ่ฎพ็ฝฎๅŠ ่ฝฝๆ็คบๆ–‡ๅญ—
         *
         * @param resId
         */
        fun setLoadingText(resId: Int) {
            this.loadingText = mContext!!.getString(resId)
            if (tvLoadingMsg != null) {
                tvLoadingMsg!!.text = this.loadingText
            }
        }
    
        /**
         * ่ฎพ็ฝฎๅŠ ่ฝฝๆ็คบๆ–‡ๅญ—
         *
         * @param loadingText
         */
        fun setLoadingText(loadingText: String) {
            this.loadingText = loadingText
            if (tvLoadingMsg != null) {
                tvLoadingMsg!!.text = this.loadingText
            }
        }
    
        /**
         * ๆ˜พ็คบๆญค่ง†ๅ›พ
         */
        fun show() {
            this.visibility = View.VISIBLE
        }
    
        /**
         * ้š่—ๆญค่ง†ๅ›พ
         */
        fun hide() {
            this.visibility = View.GONE
        }
    
        /**
         * ่ฎพ็ฝฎ้‡ๆ–ฐๅŠ ่ฝฝ็›‘ๅฌไบ‹ไปถ
         *
         * @param listener
         */
        fun setOnReloadListener(listener: OnReloadListener) {
            this.onReloadListener = listener
        }
    
    
        interface OnReloadListener {
            fun onReload()
        }
    
        companion object {
            const val TYPE_EMPTY = 0 // ้กต้ขไธบ็ฉบ๏ผŒๆฒกๆœ‰ๆ•ฐๆฎๆ—ถๅฑ•็คบ
            const val TYPE_LOADING = 1 // ๆญฃๅœจๅŠ ่ฝฝ่ง†ๅ›พ
            const val TYPE_RELOAD = 2 // ๅŠ ่ฝฝๅคฑ่ดฅ๏ผŒๆ˜พ็คบ้‡ๆ–ฐๅŠ ่ฝฝ่ง†ๅ›พ
        }

    10ใ€ShapeImageView

    package๏ผšcn.onestravel.library.kotlin.base.view

    ่‡ชๅฎšไน‰็Ÿฉๅฝขๅ’Œๅœ†ๅฝขImageView๏ผŒๅฎž็Žฐๅธฆ่พนๆก†็š„ๅœ†่ง’็ŸฉๅฝขImageViewๆˆ–ๅœ†ๅฝขImageVIew

    viewShape็š„ๅ€ผไธบ๏ผš

    ๅ€ผ ่ฏดๆ˜Ž
    SHAPE_REC ็ŸฉๅฝขImageView
    SHAPE_CIRCLE ๅœ†ๅฝขImageView
    SHAPE_OVAL ๆคญๅœ†ImageView

    /**
     * ่ฎพ็ฝฎImageView็š„ๅฝขๅผ๏ผŒๅœ†่ง’็Ÿฉๅฝข๏ผŒๅœ†ๅฝข๏ผŒๆˆ–ๆคญๅœ†
     **/
    var shape = SHAPE_REC: Int
            get() = shape
            set(shape) {
                this.shape = shape
                invalidate()
            }
    /**
     * ่ฎพ็ฝฎImageView่พนๆก†้ขœ่‰ฒ
     **/
     var borderColor: Int
            get() = mBorderColor
            set(mBorderColor) {
                this.mBorderColor = mBorderColor
                mBorderPaint.color = mBorderColor
                invalidate()
            }
    	/**
     	 * ่ฎพ็ฝฎImageView็š„ๅœ†่ง’
     	 **/
        var roundRadius: Float
            get() = mRoundRadius
            set(mRoundRadius) {
                this.mRoundRadius = mRoundRadius
                invalidate()
            }
    	/**
     	 * ่ฎพ็ฝฎImageView็š„่พนๆก†ๅฎฝๅบฆ
     	 **/
        fun setBorderSize(mBorderSize: Int) {
            this.borderSize = mBorderSize.toFloat()
            mBorderPaint.strokeWidth = mBorderSize.toFloat()
            initRect()
            invalidate()
        }
    	/**
     	 * ่ฎพ็ฝฎImageView็š„ๅ›พ็‰‡่ต„ๆบ
     	 **/
    override fun setImageResource(resId: Int) {
            super.setImageResource(resId)
            mBitmap = ImageUtils.getBitmapFromDrawable(drawable)
            setupBitmapShader()
        }
    	/**
     	 * ่ฎพ็ฝฎImageView็š„Drawable
     	 **/		
        override fun setImageDrawable(drawable: Drawable?) {
            super.setImageDrawable(drawable)
            mBitmap = ImageUtils.getBitmapFromDrawable(drawable)
            setupBitmapShader()
        }
    
        

    ไบŒใ€้‡‡็”จRxJava+Retrofitๆžถๆž„ๅฐ่ฃ…็š„ๅ…ณไบŽHttp่ฏทๆฑ‚ไปฅๅŠ็”Ÿๅ‘ฝๅ‘จๆœŸๅค„็†็š„ๆ–‡ไปถไป‹็ป

    1ใ€BaseRxActivity

    package๏ผšcn.onestravel.library.kotlin.rxrequest.activity

    ็ปงๆ‰ฟ่‡ชBaseActivity ๏ผŒ้’ˆๅฏนRxJavaๅค„็†ไบ†็›ธๅฏนๅบ”็š„็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผŒๅŒๆ—ถๆ‹ฅๆœ‰BaseActivity็š„ๆ‰€ๆœ‰็‰นๆ€งใ€‚

    ็”Ÿๅ‘ฝๅ‘จๆœŸๅค„็†๏ผš

    abstract class BaseRxActivity : BaseActivity(), LifecycleProvider<ActivityEvent> {
        private val lifecycleSubject:BehaviorSubject<ActivityEvent> = BehaviorSubject.create()
    
        @CheckResult
        override fun lifecycle(): Observable<ActivityEvent> {
            return lifecycleSubject.hide()
        }
    
        @CheckResult
        override fun <T> bindUntilEvent(event: ActivityEvent): LifecycleTransformer<T> {
            return RxLifecycle.bindUntilEvent(lifecycleSubject, event)
        }
    
        @CheckResult
        override fun <T> bindToLifecycle(): LifecycleTransformer<T> {
            return RxLifecycleAndroid.bindActivity(lifecycleSubject)
        }
    
        @CallSuper
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            lifecycleSubject.onNext(ActivityEvent.CREATE)
        }
    
        @CallSuper
        override fun onStart() {
            super.onStart()
            lifecycleSubject.onNext(ActivityEvent.START)
        }
    
        @CallSuper
        override fun onResume() {
            super.onResume()
            lifecycleSubject.onNext(ActivityEvent.RESUME)
        }
    
        @CallSuper
        override fun onPause() {
            lifecycleSubject.onNext(ActivityEvent.PAUSE)
            super.onPause()
        }
    
        @CallSuper
        override fun onStop() {
            lifecycleSubject.onNext(ActivityEvent.STOP)
            super.onStop()
        }
    
        @CallSuper
        override fun onDestroy() {
            lifecycleSubject.onNext(ActivityEvent.DESTROY)
            super.onDestroy()
        }
    }

    2ใ€BaseRxListActivity

    package๏ผšcn.onestravel.library.kotlin.rxrequest.activity

    ็ปงๆ‰ฟ่‡ชBaseListActivity ๏ผŒ้’ˆๅฏนRxJavaๅค„็†ไบ†็›ธๅฏนๅบ”็š„็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผŒๅŒๆ—ถๆ‹ฅๆœ‰BaseListActivityไธ‹ๆ‹‰ๅˆทๆ–ฐ๏ผŒไธŠๆ‹‰ๅŠ ่ฝฝ็š„ๆ‰€ๆœ‰็‰นๆ€งใ€‚

    3ใ€BaseRxFragment

    package๏ผšcn.onestravel.library.kotlin.rxrequest.fragment

    ็ปงๆ‰ฟ่‡ชBaseFragment ๏ผŒ้’ˆๅฏนRxJavaๅค„็†ไบ†็›ธๅฏนๅบ”็š„็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผŒๅŒๆ—ถๆ‹ฅๆœ‰BaseFragment็š„ๆ‰€ๆœ‰็‰นๆ€งใ€‚

    ็”Ÿๅ‘ฝๅ‘จๆœŸๅค„็†๏ผš

    abstract class BaseRxFragment : BaseFragment(), LifecycleProvider<FragmentEvent> {
        private val lifecycleSubject:BehaviorSubject<FragmentEvent> = BehaviorSubject.create()
    
        override fun lifecycle(): Observable<FragmentEvent> {
            return lifecycleSubject.hide()
        }
    
        @CheckResult
        override fun <T> bindUntilEvent(event: FragmentEvent): LifecycleTransformer<T> {
            return RxLifecycle.bindUntilEvent(lifecycleSubject, event)
        }
    
        @CheckResult
        override fun <T> bindToLifecycle(): LifecycleTransformer<T> {
            return RxLifecycleAndroid.bindFragment(lifecycleSubject)
        }
    
        @CallSuper
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            lifecycleSubject.onNext(FragmentEvent.CREATE)
        }
    
    
        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
            lifecycleSubject.onNext(FragmentEvent.CREATE_VIEW)
            return super.onCreateView(inflater, container, savedInstanceState)
        }
    
    
        @CallSuper
        override fun onStart() {
            super.onStart()
            lifecycleSubject.onNext(FragmentEvent.START)
        }
    
        @CallSuper
        override fun onResume() {
            super.onResume()
            lifecycleSubject.onNext(FragmentEvent.RESUME)
        }
    
        @CallSuper
        override fun onPause() {
            lifecycleSubject.onNext(FragmentEvent.PAUSE)
            super.onPause()
        }
    
        @CallSuper
        override fun onStop() {
            lifecycleSubject.onNext(FragmentEvent.STOP)
            super.onStop()
        }
    
        override fun onDestroyView() {
            lifecycleSubject.onNext(FragmentEvent.DESTROY_VIEW)
            super.onDestroyView()
        }
    
        @CallSuper
        override fun onDestroy() {
            lifecycleSubject.onNext(FragmentEvent.DESTROY)
            super.onDestroy()
        }
    }
    

    4ใ€BaseRxListFragment

    package๏ผšcn.onestravel.library.kotlin.rxrequest.fragment

    ็ปงๆ‰ฟ่‡ชBaseListFragment ๏ผŒ้’ˆๅฏนRxJavaๅค„็†ไบ†็›ธๅฏนๅบ”็š„็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผŒๅŒๆ—ถๆ‹ฅๆœ‰BaseListFragmentไธ‹ๆ‹‰ๅˆทๆ–ฐ๏ผŒไธŠๆ‹‰ๅŠ ่ฝฝ็š„ๆ‰€ๆœ‰็‰นๆ€งใ€‚

    5ใ€BaseObserver<T: ResponseResult>

    package๏ผšcn.onestravel.library.kotlin.rxrequest.common

    RxJava+Retrofit ่ฏทๆฑ‚็š„่ง‚ๅฏŸ่€…๏ผŒ่ฟ”ๅ›ž็‰นๅฎšๆ•ฐๆฎ็ป“ๆž„็š„ๆ•ฐๆฎ๏ผŒๅนถ่ฟ›่กŒ็›ธๅบ”็š„ๅค„็†ใ€‚

    ๅ…ทไฝ“ๅฎž็Žฐๅฆ‚ไธ‹๏ผš

    /**
     * @name cn.onestravel.library.kotlin.rxrequest.common.OneObserver
     * @description ่ฏทๆฑ‚่ฟ”ๅ›ž็ป“ๆžœ๏ผŒ่ฟ”ๅ›žjsonๆ•ฐๆฎๅฟ…้กป็ฌฆๅˆ {"code":"0000","msg":""}
     * @createTime 2018/12/12 17:00
     * @author onestravel
     * @version 1.0.0
     */
    abstract class BaseObserver<T : ResponseResult> : Observer<T> {
    
        /**
         * ่ฏทๆฑ‚ๅผ€ๅง‹ ๅค„็†ๅŸบๆœฌ็š„loadingๆก†็š„ๆ˜พ็คบ็ญ‰
         *
         * @param d
         */
        fun onStart(d: Disposable) {
            Log.e(
                TAG,
                "===========ๅ•ไธชๆŽฅๅฃ่ฏทๆฑ‚ๅผ€ๅง‹========================================="
            )
        }
    
        /**
         * ๆญคๆ–นๆณ•ๅฟ…้กปๅฎž็Žฐ
         *
         * @param result ่ฏทๆฑ‚ๆˆๅŠŸ็š„็ป“ๆžœ
         */
        abstract fun onSuccess(result: T)
    
        /**
         * ่ฏทๆฑ‚ๅคฑ่ดฅ
         *
         * @param code ้”™่ฏฏ็ 
         * @param msg  ้”™่ฏฏๆ็คบ่ฏญ
         */
        fun onFailure(code: String, msg: String?) {
            Log.e(
                TAG,
                "ๆŽฅๅฃ่ฏทๆฑ‚ๅคฑ่ดฅ===code = " + code + "errorMsg =" + msg 
            )
        }
    
        /**
         * ่ฏทๆฑ‚้ƒฝๅฎŒๆˆๆ—ถไน‹่กŒๆญคๆ–นๆณ•
         */
        fun onFinish() {
    
        }
    
        override fun onSubscribe(d: Disposable) {
            onStart(d)
        }
    
        override fun onNext(result: T) {
            if (BaseResponse.REQUEST_OK == result.code) {
                onSuccess(result)
                Log.i(TAG, "่ฏทๆฑ‚ๆˆๅŠŸresponseBody====" + JSON.toJSONString(result))
            } else {
                onFailure(result.code, result.msg)
            }
    
        }
    
        override fun onError(e: Throwable) {
            var errorMsg = ""
            var errorCode = 0
            if (e is HttpException) {
                val httpException = e as HttpException
                errorCode = httpException.response().code()
                if (404 == errorCode || 500 == errorCode) {
                    errorMsg = "่ฏทๆฑ‚ๅผ‚ๅธธ๏ผŒ่ฏท็จๅ€™้‡่ฏ•๏ผ"
                } else {
    
                }
    
            } else {
                //todo ่ฎพ็ฝฎๅ›บๅฎš็š„้”™่ฏฏ็ ๅŠ้”™่ฏฏๆ็คบ
            }
            onFailure(errorCode.toString(), errorMsg)
        }
    
        override fun onComplete() {
            onFinish()
        }
    
        companion object {
            private val TAG = "request"
        }
    }
    

    BaseResponse:

    /**
     * @name cn.onestravel.library.kotlin.rxrequest.common.OneResponse
     * @description ่ฏทๆฑ‚่ฟ”ๅ›ž็ป“ๆžœๆ•ฐๆฎๅŸบ็ฑป
     * @createTime 2018/12/12 17:00
     * @author onestravel
     * @version 1.0.0
     */
    open class BaseResponse(val code: String = "0000", val msg: String = ""): Serializable {
        companion object {
            val REQUEST_OK = "0000"  //่ฏทๆฑ‚ๆˆๅŠŸ็š„code็ 
            val REQUEST_ERROR = "-1" //่ฏทๆฑ‚ๅคฑ่ดฅ็š„code็ 
        }
    }

    ResponseResult:

    /**
     * @name cn.onestravel.library.kotlin.rxrequest.common.ResponseResult
     * @description ่ฏทๆฑ‚่ฟ”ๅ›ž็ป“ๆžœๆ•ฐๆฎ ็ฌฆๅˆ {"code":"0000","msg":"","data":{},"datas":[]} ็š„ๅŸบ็ฑป
     * @createTime 2018/12/12 17:00
     * @author onestravel
     * @version 1.0.0
     */
    class ResponseResult :BaseResponse(), Serializable

    6ใ€BaseObserver1<DATA: Serializable>

    package๏ผšcn.onestravel.library.kotlin.rxrequest.common

    RxJava+Retrofit ่ฏทๆฑ‚็š„่ง‚ๅฏŸ่€…๏ผŒ่ฟ”ๅ›ž็‰นๅฎšๆ•ฐๆฎ็ป“ๆž„็š„ๆ•ฐๆฎ๏ผŒๅนถ่ฟ›่กŒ็›ธๅบ”็š„ๅค„็†ใ€‚

    ๅ…ทไฝ“ๅฎž็Žฐๅฆ‚ไธ‹๏ผš

    /**
     * @name cn.onestravel.library.kotlin.rxrequest.common.OneObserver
     * @description ่ฏทๆฑ‚่ฟ”ๅ›ž็ป“ๆžœ๏ผŒ่ฟ”ๅ›žjsonๆ•ฐๆฎๅฟ…้กป็ฌฆๅˆ  {"code":"0000","msg":"","data":{},"datas":[]},data ๅ’Œ datas ็š„ๆ•ฐๆฎ bean ็›ธๅŒ
     * @createTime 2018/12/12 17:00
     * @author onestravel
     * @version 1.0.0
     */
    abstract class BaseObserver1<DATA : Serializable> : Observer<ResponseResult1<DATA>> {
    
        /**
         * ่ฏทๆฑ‚ๅผ€ๅง‹ ๅค„็†ๅŸบๆœฌ็š„loadingๆก†็š„ๆ˜พ็คบ็ญ‰
         *
         * @param d
         */
        fun onStart(d: Disposable) {
            Log.e(
                TAG,
                "===========ๅ•ไธชๆŽฅๅฃ่ฏทๆฑ‚ๅผ€ๅง‹  =========="
            )
        }
    
        /**
         * ๆญคๆ–นๆณ•ๅฟ…้กปๅฎž็Žฐ
         *
         * @param result ่ฏทๆฑ‚ๆˆๅŠŸ็š„็ป“ๆžœ
         */
        abstract fun onSuccess(result: ResponseResult1<DATA>)
    
        /**
         * ่ฏทๆฑ‚ๅคฑ่ดฅ
         *
         * @param code ้”™่ฏฏ็ 
         * @param msg  ้”™่ฏฏๆ็คบ่ฏญ
         */
        fun onFailure(code: String, msg: String?) {
            Log.e(
                TAG,
                "ๆŽฅๅฃ่ฏทๆฑ‚ๅคฑ่ดฅ============code = " + code + "errorMsg =" + msg    )
        }
    
        /**
         * ่ฏทๆฑ‚้ƒฝๅฎŒๆˆๆ—ถไน‹่กŒๆญคๆ–นๆณ•
         */
        open fun onFinish() {
    
        }
    
        override fun onSubscribe(d: Disposable) {
            onStart(d)
        }
    
        override fun onNext(result: ResponseResult1<DATA>) {
            if (BaseResponse.REQUEST_OK == result.code) {
                onSuccess(result)
                Log.i(TAG, "่ฏทๆฑ‚ๆˆๅŠŸresponseBody====" + JSON.toJSONString(result))
            } else {
                onFailure(result.code, result.msg)
            }
    
        }
    
        override fun onError(e: Throwable) {
            var errorMsg = ""
            var errorCode = 0
            if (e is HttpException) {
                val httpException = e as HttpException
                errorCode = httpException.response().code()
                if (404 == errorCode || 500 == errorCode) {
                    errorMsg = "่ฏทๆฑ‚ๅผ‚ๅธธ๏ผŒ่ฏท็จๅ€™้‡่ฏ•๏ผ"
                } else {
    
                }
    
            } else {
                //todo ่ฎพ็ฝฎๅ›บๅฎš็š„้”™่ฏฏ็ ๅŠ้”™่ฏฏๆ็คบ
            }
            onFailure(errorCode.toString(), errorMsg)
        }
    
        override fun onComplete() {
            onFinish()
        }
    
        companion object {
            private val TAG = "request"
        }
    }
    

    ResponseResult1:

    /**
     * @name cn.onestravel.library.kotlin.rxrequest.common.ResponseResult
     * @description ่ฏทๆฑ‚่ฟ”ๅ›ž็ป“ๆžœๆ•ฐๆฎ ็ฌฆๅˆ {"code":"0000","msg":"","data":{},"datas":[]} ็š„ๅŸบ็ฑป
     * @createTime 2018/12/12 17:00
     * @author onestravel
     * @version 1.0.0
     */
    class ResponseResult1<DATA:Serializable>(
        val data: DATA?,
        val datas: MutableList<DATA>? = ArrayList()
    ) :BaseResponse(), Serializable
    
    

    7ใ€BaseObserver2<DATA : Serializable,ITEM:Serializable>

    package๏ผšcn.onestravel.library.kotlin.rxrequest.common

    RxJava+Retrofit ่ฏทๆฑ‚็š„่ง‚ๅฏŸ่€…๏ผŒ่ฟ”ๅ›ž็‰นๅฎšๆ•ฐๆฎ็ป“ๆž„็š„ๆ•ฐๆฎ๏ผŒๅนถ่ฟ›่กŒ็›ธๅบ”็š„ๅค„็†ใ€‚

    ๅ…ทไฝ“ๅฎž็Žฐๅฆ‚ไธ‹๏ผš

    package cn.onestravel.library.kotlin.rxrequest.common
    
    import android.util.Log
    import io.reactivex.Observer
    import io.reactivex.disposables.Disposable
    import retrofit2.HttpException
    import java.io.Serializable
    
    /**
     * @name cn.onestravel.library.kotlin.rxrequest.common.OneObserver2
     * @description ่ฏทๆฑ‚่ฟ”ๅ›ž็ป“ๆžœ๏ผŒ่ฟ”ๅ›žjsonๆ•ฐๆฎๅฟ…้กป็ฌฆๅˆ {"code":"0000","msg":"","data":{},"datas":[]},data ๅ’Œ datas ็š„ๆ•ฐๆฎ bean ๅฏไปฅไธ็›ธๅŒ
     * @createTime 2018/12/12 17:00
     * @author onestravel
     * @version 1.0.0
     */
    abstract class BaseObserver2<DATA : Serializable,ITEM:Serializable> : Observer<ResponseResult2<DATA,ITEM>>, ObserverResult<ResponseResult2<DATA,ITEM>> {
        /**
         * ่ฏทๆฑ‚ๅผ€ๅง‹ ๅค„็†ๅŸบๆœฌ็š„loadingๆก†็š„ๆ˜พ็คบ็ญ‰
         *
         * @param d
         */
        override fun onStart(d: Disposable) {
            Log.e(
                 BaseObserver2.TAG,
                "===========ๅ•ไธชๆŽฅๅฃ่ฏทๆฑ‚ๅผ€ๅง‹  =========="
            )
        }
    
        /**
         * ๆญคๆ–นๆณ•ๅฟ…้กปๅฎž็Žฐ
         *
         * @param result ่ฏทๆฑ‚ๆˆๅŠŸ็š„็ป“ๆžœ
         */
        abstract override fun onSuccess(result: ResponseResult2<DATA, ITEM>)
    
        /**
         * ่ฏทๆฑ‚ๅคฑ่ดฅ
         *
         * @param code ้”™่ฏฏ็ 
         * @param msg  ้”™่ฏฏๆ็คบ่ฏญ
         */
        override fun onFailure(code: String, msg: String?) {
            Log.e(
                 BaseObserver2.TAG,
                "ๆŽฅๅฃ่ฏทๆฑ‚ๅคฑ่ดฅ============code = " + code + "errorMsg =" + msg    )
        }
    
        /**
         * ่ฏทๆฑ‚้ƒฝๅฎŒๆˆๆ—ถไน‹่กŒๆญคๆ–นๆณ•
         */
        override fun onFinish() {
    
        }
    
        override fun onSubscribe(d: Disposable) {
            onStart(d)
        }
        override fun onNext(baseObject: ResponseResult2<DATA,ITEM>) {
            //        Log.i("responseBody====",)
            if (BaseResponse.REQUEST_OK == baseObject.code) {
                onSuccess(baseObject)
            } else {
                onFailure(baseObject.code, baseObject.msg)
            }
        }
    
        /**
         *
         */
        override fun onError(e: Throwable) {
            var errorMsg = ""
            var errorCode = 0
            if (e is HttpException) {
                val httpException = e as HttpException
                errorCode = httpException.response().code()
                if (404 == errorCode || 500 == errorCode) {
                    errorMsg = "่ฏทๆฑ‚ๅผ‚ๅธธ๏ผŒ่ฏท็จๅ€™้‡่ฏ•๏ผ"
                } else {
    
                }
    
            } else {
                //todo ่ฎพ็ฝฎๅ›บๅฎš็š„้”™่ฏฏ็ ๅŠ้”™่ฏฏๆ็คบ
            }
            onFailure(errorCode.toString(), errorMsg)
        }
    
        override fun onComplete() {
            onFinish()
        }
    
        companion object {
            private val TAG = "RequestBaseObserver2"
        }
    }
    

    ResponseResult2:

    /**
     * @name cn.onestravel.library.kotlin.rxrequest.common.ResponseResult
     * @description ่ฏทๆฑ‚่ฟ”ๅ›ž็ป“ๆžœๆ•ฐๆฎ ็ฌฆๅˆ {"code":"0000","msg":"","data":{},"datas":[]} ็š„ๅŸบ็ฑป
     * @createTime 2018/12/12 17:00
     * @author onestravel
     * @version 1.0.0
     */
    class ResponseResult2<DATA:Serializable,ITEM:Serializable>(
        val data: DATA?,
        val datas: MutableList<ITEM>? = ArrayList()
    ) :BaseResponse(), Serializable
    
    

    8ใ€BaseLoader

    package๏ผšcn.onestravel.library.kotlin.rxrequest.loader

    ๅ…ฌๅ…ฑ็š„Loader๏ผŒๅค„็†observe้’ˆๅฏน่ฏทๆฑ‚่ฟ›่กŒ็บฟ็จ‹ๅˆ‡ๆข

    abstract class BaseLoader<S : BaseService> {
        protected val mServiceManager: RetrofitServiceManager by lazy { RetrofitServiceManager.INSTANCE }
        protected val mService: S by lazy { createService() }
    
        /**
         * ๅˆ›ๅปบ Service ๅฎžไพ‹
         */
        abstract fun createService(): S
    
        /**
         * ่ฎพ็ฝฎObservable็š„ๅทฅไฝœ็บฟ็จ‹
         * @param observable
         * @param <T>
         * @return
        </T> */
        fun <T> observe(observable: Observable<T>): Observable<T> {
            return observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
        }
    
    
    }
    

    9ใ€BaseService

    package๏ผšcn.onestravel.library.kotlin.rxrequest.service

    ๆ‰€ๆœ‰ Retrofit ่ฏทๆฑ‚็š„ Service ็š„ๆŽฅๅฃๅŸบ็ฑป๏ผŒ็›ฎๅ‰ๅช็”จไบŽ่ง„่Œƒๅญ็ฑป๏ผŒๅฏๅฃฐๆ˜Žๅฏนๅบ”ๅ…ฌ็”จๆ–นๆณ•

    10ใ€RetrofitServiceManager

    package๏ผšcn.onestravel.library.kotlin.rxrequest.service

    ็”ŸๆˆๆŽฅๅฃserviceๅฎžไพ‹็š„็ฎก็†็ฑป๏ผŒๅˆๅง‹ๅŒ–Retrofit ๅฎžไพ‹๏ผŒ่ฎพ็ฝฎ่ฏทๆฑ‚็›ธๅ…ณ็š„ไธ€ไบ›ๆ‹ฆๆˆชๅ™จใ€่ถ…ๆ—ถๆ—ถ้—ด็ญ‰้…็ฝฎ๏ผŒๅฎšไน‰Http่ฏทๆฑ‚็š„ๅ…ฌๅ…ฑURL

    /**
     * @name cn.onestravel.library.kotlin.rxrequest.service.RetrofitServiceManager
     * @description ็”ŸๆˆๆŽฅๅฃๅฎžไพ‹็š„็ฎก็†็ฑป
     * @createTime 2018/12/12 17:00
     * @author onestravel
     * @version 1.0.0
     */
    class RetrofitServiceManager private constructor() {
        private val mRetrofit: Retrofit
        init {
            val interceptorBuild = HttpCommonInterceptor.Builder()
         
            val logging = HttpLoggingInterceptor()
            logging.level = HttpLoggingInterceptor.Level.BODY
            val okHttpClientBuild = OkHttpClient.Builder()
            okHttpClientBuild.connectTimeout(CONNECTION_TIMEOUT.toLong(), TimeUnit.SECONDS)
                .readTimeout(READ_TIMEOUT.toLong(), TimeUnit.SECONDS)
                .writeTimeout(WRITE_TIMEOUT.toLong(), TimeUnit.SECONDS)
                .addInterceptor(interceptorBuild.build())//ๆ‹ฆๆˆชๅ™จๆทปๅŠ ๅ…ฌๅ…ฑ่ฏทๆฑ‚ๅ‚ๆ•ฐ
                .addInterceptor(RetryInterceptor(2))//้‡่ฏ•ไธ‰ๆฌก็š„ๆ‹ฆๆˆช
                            .addInterceptor(logging)//่ฏทๆฑ‚ๆ—ฅๅฟ—ๆ‰“ๅฐ
    
            //ๅˆๅง‹ๅŒ–Retrofit
            mRetrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(okHttpClientBuild.build())
                .build()
    
        }
    
    
    
        /**
         * ็”Ÿๆˆๅฏนๅบ”ๆŽฅๅฃ็š„ๅฎžไพ‹
         *
         * @param service
         * @param <T>
         * @return
        </T> */
        fun <T:BaseService> create(service: Class<T>): T {
            return mRetrofit.create(service)
    
        }
    
        companion object {
            val INSTANCE by lazy { RetrofitServiceManager() }
            private const val CONNECTION_TIMEOUT = 5
            private const val READ_TIMEOUT = 20
            private const val WRITE_TIMEOUT = 10
            private const val BASE_URL = "http://192.168.1.12:9090/"
        }
    }
    

    ไธ‰ใ€้‡‡็”จMvpๆžถๆž„ๅฐ่ฃ…็š„ๆ–‡ไปถไป‹็ป

    1ใ€BaseMvpActivity<V : BaseMvpView, P : BaseMvpPresenter>

    package๏ผšcn.onestravel.library.kotlin.mvp.activity

    ๆ‰€ๆœ‰Mvpๆžถๆž„็š„ Activity ็š„ๅŸบ็ฑป,่‡ชBaseActivity ๏ผŒๆ‹ฅๆœ‰BaseActivity็š„ๆ‰€ๆœ‰็‰นๆ€ง,ๅค„็†ไบ†Pๅฑ‚็š„็›ธๅ…ณ็”Ÿๅ‘ฝๅ‘จๆœŸใ€‚

    /**
     * @name  BaseMvpActivity
     * @description ๆ‰€ๆœ‰Mvpๆžถๆž„็š„ Activity ็š„ๅŸบ็ฑป
     * @createTime 2018/12/12 17:00
     * @author onestravel
     * @version 1.0.0
     */
    abstract class BaseMvpActivity<V : BaseMvpView, P : BaseMvpPresenter<V>> : BaseActivity(), BaseMvpView {
        private val presenter by lazy { createPresenter() }
        private var mLoadingDialog: LoadingDialog? = null
        protected abstract fun createPresenter(): P
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            if (presenter == null) {
                throw  NullPointerException("Presenter is null! Do you return null in createPresenter()?")
            }
            presenter.onMvpAttachView(this as V, savedInstanceState)
        }
    
    
        override fun onStart() {
            super.onStart()
            presenter.let {
                it.onMvpStart()
            }
        }
    
        override fun onResume() {
            super.onResume()
            presenter.let {
                it.onMvpResume()
            }
        }
    
        override fun onPause() {
            presenter.let {
                it.onMvpPause()
            }
            super.onPause()
        }
    
        override fun onStop() {
            presenter.let {
                it.onMvpStop()
            }
            super.onStop()
        }
    
    
        override fun onSaveInstanceState(outState: Bundle?) {
            super.onSaveInstanceState(outState)
            presenter?.let {
                it.onMvpSaveInstanceState(outState)
            }
        }
    
        override fun onDestroy() {
            presenter?.let {
                it.onMvpDetachView(false)
                it.onMvpDestroy()
            }
            mLoadingDialog?.let {
                it.destroy()
                mLoadingDialog = null
            }
            super.onDestroy()
        }
    
        override fun showLoading(content: String?) {
            if (mLoadingDialog == null) {
                mLoadingDialog = LoadingDialog.getInstance(this)
                mLoadingDialog!!.title = content?:"ๆญฃๅœจๅŠ ่ฝฝ..."
                if (!mLoadingDialog!!.isShowing) {
                    mLoadingDialog!!.show()
                }
            }
        }
    
        override fun hideLoading() {
            mLoadingDialog?.let {
                mLoadingDialog!!.dismiss()
            }
        }
    
        override fun onResponseError(msg: String?) {
            msg?.let {
                showToast(msg)
            }
        }
    
    }

    2ใ€BaseMvpListActivity<V : BaseMvpView, P : BaseMvpPresenter>

    package๏ผšcn.onestravel.library.kotlin.mvp.activity

    ๆ‰€ๆœ‰Mvpๆžถๆž„็š„ ListActivity ็š„ๅŸบ็ฑป,่‡ชBaseListActivity ๏ผŒๆ‹ฅๆœ‰BaseListActivity็š„ๆ‰€ๆœ‰็‰นๆ€ง๏ผŒๅนถไธ”ๅค„็†ไบ†Pๅฑ‚็š„็›ธๅ…ณ็”Ÿๅ‘ฝๅ‘จๆœŸใ€‚

    3ใ€BaseRxMvpActivity<V : BaseMvpView, P : BaseMvpPresenter>

    package๏ผšcn.onestravel.library.kotlin.mvp.activity

    ๆ‰€ๆœ‰Mvpๆžถๆž„็š„ ้‡‡็”จRxJava+Retrofit ่ฏทๆฑ‚็š„Activity ็š„ๅŸบ็ฑป๏ผŒ็ปงๆ‰ฟ่‡ชBaseRxActivity ๏ผŒๆ‹ฅๆœ‰BaseRxActivity็š„ๆ‰€ๆœ‰็‰นๆ€ง๏ผŒๅนถไธ”ๅค„็†ไบ†Pๅฑ‚็š„็›ธๅ…ณ็”Ÿๅ‘ฝๅ‘จๆœŸใ€‚

    4ใ€BaseRxMvpListActivity<V : BaseMvpView, P : BaseMvpPresenter>

    package๏ผšcn.onestravel.library.kotlin.mvp.activity

    ๆ‰€ๆœ‰Mvpๆžถๆž„็š„ ้‡‡็”จRxJava+Retrofit ่ฏทๆฑ‚็š„ๅธฆๆœ‰ๅˆ—่กจ็š„Activity๏ผŒ็ปงๆ‰ฟ่‡ชBaseRxListActivity ๏ผŒๆ‹ฅๆœ‰BaseRxListActivity็š„ๆ‰€ๆœ‰็‰นๆ€ง๏ผŒๅนถไธ”ๅค„็†ไบ†Pๅฑ‚็š„็›ธๅ…ณ็”Ÿๅ‘ฝๅ‘จๆœŸใ€‚

    5ใ€Fragment ๆœ‰ไธŽๅ‰4ไธชActivityๅŠŸ่ƒฝ็›ธๅŒFragment๏ผŒๅฐฑไธๅคšๅšไป‹็ปไบ†ใ€‚

    package๏ผšcn.onestravel.library.kotlin.mvp.fragment

    6ใ€BaseMvpModel

    package๏ผšcn.onestravel.library.kotlin.mvp.model

    Mvpๆจกๅผไธญๆ‰€ๆœ‰Modelๅฑ‚็š„ๅŸบ็ฑป๏ผŒๆ˜ฏไธ€ไธชๆŽฅๅฃ๏ผŒๅฏไปฅๅฃฐๆ˜Žๅ…ฑๅŒ็š„ๆ–นๆณ•๏ผŒไบค็”ฑๅญ็ฑปๅŽปๅฎž็Žฐใ€‚

    7ใ€BaseMvpPresenter

    package๏ผšcn.onestravel.library.kotlin.mvp.presenter

    Mvpๆจกๅผไธญๆ‰€ๆœ‰presenterๅฑ‚็š„ๅŸบ็ฑป๏ผŒๆ˜ฏไธ€ไธชๆŽฅๅฃ๏ผŒๅฃฐๆ˜Žไบ†presenterๅฑ‚็›ธๅ…ณ็š„็”Ÿๅ‘ฝๅ‘จๆœŸๆ–นๆณ•๏ผŒ็”ฑๅญ็ฑปๅŽปๅฎž็Žฐใ€‚

    /**
     * @name  BaseMvpPresenterImpl
     * @description ๆ‰€ๆœ‰็•Œ้ขpresenter็š„ๆŽฅๅฃ็ฑป
     * @createTime 2018/12/12 16:27
     * @author onestravel
     * @version 1.0.0
     */
    
    interface BaseMvpPresenter<in V : BaseMvpView> {
        fun onMvpAttachView(view: V, savedInstanceState: Bundle?)
    
        fun onMvpStart()
    
        fun onMvpResume()
    
        fun onMvpPause()
    
        fun onMvpStop()
    
        fun onMvpSaveInstanceState(savedInstanceState: Bundle?)
    
        fun onMvpDetachView(retainInstance: Boolean)
    
        fun onMvpDestroy()
    
    }

    8ใ€BaseMvpPresenterImpl<V: BaseMvpView>

    package๏ผšcn.onestravel.library.kotlin.mvp.presenter.impl

    Mvpๆจกๅผไธญๆ‰€ๆœ‰presenterๅฑ‚็š„ๆŽฅๅฃ็š„ๅฎž็Žฐ็ฑป๏ผŒๅฏนpresenterๅฑ‚็›ธๅ…ณ็š„็”Ÿๅ‘ฝๅ‘จๆœŸๆ–นๆณ•่ฟ›่กŒๅฎž็Žฐ๏ผ›ๅนถไธ”ๅฎž็ŽฐไธŽViewๅฑ‚็š„็ป‘ๅฎš๏ผŒๆŒๆœ‰Viewๅฑ‚็š„ๅผ•็”จใ€‚

    /**
     * @name  BaseMvpPresenterImpl
     * @description ๆ‰€ๆœ‰็•Œ้ขpresenter็š„ๆŽฅๅฃ็ฑป
     * @createTime 2018/12/12 16:27
     * @author onestravel
     * @version 1.0.0
     */
    
    interface BaseMvpPresenter<in V : BaseMvpView> {
        fun onMvpAttachView(view: V, savedInstanceState: Bundle?)
    
        fun onMvpStart()
    
        fun onMvpResume()
    
        fun onMvpPause()
    
        fun onMvpStop()
    
        fun onMvpSaveInstanceState(savedInstanceState: Bundle?)
    
        fun onMvpDetachView(retainInstance: Boolean)
    
        fun onMvpDestroy()
    
    }

    9ใ€BaseMvpView

    package๏ผšcn.onestravel.library.kotlin.mvp.view

    Mvpๆจกๅผไธญๆ‰€ๆœ‰Viewๅฑ‚็š„ๆŽฅๅฃ็ฑป๏ผŒๅฃฐๆ˜Žไบ†ไธ€ไบ›Viewๅฑ‚ๅธธ็”จ็š„ๅŠ ่ฝฝ่ฟ›ๅบฆๆ˜พ็คบไธŽ้š่—๏ผŒ่ฏทๆฑ‚ๅคฑ่ดฅๆ็คบ็ญ‰ๅ…ฌ็”จ็š„ๆ–นๆณ•ใ€‚

    /**
     * @name  BaseMvpPresenterImpl
     * @description ๆ‰€ๆœ‰็•Œ้ขpresenter็š„ๆŽฅๅฃ็ฑป
     * @createTime 2018/12/12 16:27
     * @author onestravel
     * @version 1.0.0
     */
    
    interface BaseMvpPresenter<in V : BaseMvpView> {
        fun onMvpAttachView(view: V, savedInstanceState: Bundle?)
    
        fun onMvpStart()
    
        fun onMvpResume()
    
        fun onMvpPause()
    
        fun onMvpStop()
    
        fun onMvpSaveInstanceState(savedInstanceState: Bundle?)
    
        fun onMvpDetachView(retainInstance: Boolean)
    
        fun onMvpDestroy()
    
    }

    ๅฃฐๆ˜Ž๏ผš

    ้’ˆๅฏนKotlin้กน็›ฎ็š„ไธ€ไบ›ๅธธ็”จๅฐ่ฃ…๏ผŒๅˆฐ่ฟ™้‡Œๅฐฑไป‹็ปๅฎŒไบ†๏ผŒๅŽ้ข่ฟ˜ไผšๅขžๅŠ MVVMๆจกๅผ็š„ไธ€ไบ›ๅฐ่ฃ…๏ผŒๆ•ฌ่ฏทๆœŸๅพ…๏ผ๏ผ

    ๅœจๅฐ่ฃ…ๆˆ–่€…ไป‹็ป่ฟ‡็จ‹ไธญ๏ผŒๅฆ‚ๆœ‰ไป€ไนˆไธๆญฃ็กฎๆˆ–่€…ไธๆ˜Ž็™ฝ็š„ๅœฐๆ–น๏ผŒๆœŸๅพ…ไธŽๆ‚จ่ฟ›่กŒไบคๆต๏ผŒๅ…ฑๅŒๆ้ซ˜๏ผ

    ่”็ณป้‚ฎไปถ๏ผšserver@onestravel.cn

    ้ธฃ่ฐข๏ผ๏ผ๏ผ

    Visit original content creator repository
    https://github.com/onestravel/kotlin-common

  • Automated-Invoice-System—VBA

    Automated-Invoice-System—VBA

    Automated Invoice Generation System Using VBA in Excel

    In an effort to enhance efficiency and accuracy in the invoicing process, I developed a fully automated invoice generation system using Visual Basic for Applications (VBA) within Microsoft Excel. This project was pivotal in streamlining the invoicing workflow, significantly reducing the time and effort required for manual data entry, and ensuring the precision of financial transactions.

    Project Overview:

    Problem Identification: The existing invoicing process was highly manual, involving repetitive data entry, which led to frequent errors and delays. With over 500 invoices generated each month, it became imperative to find a solution that could minimize these inefficiencies and reduce the error rate.

    System Design and Development:

    Utilizing VBA, I programmed an automated system that could generate invoices with just a few clicks. The system was designed to pull data from multiple sources, such as customer databases, product lists, and pricing tables, ensuring that all necessary information was accurately incorporated into each invoice. The VBA code was structured to handle complex logic, including tax calculations, discounts, and payment terms, all of which were automatically applied based on predefined rules.

    Data Integration:

    A key feature of the system was its ability to integrate real-time data from various sources. I linked Excel to external databases and other worksheets, allowing the system to update invoice details automatically whenever the source data changed. This integration not only saved time but also ensured that invoices were always generated with the most up-to-date information, enhancing the overall reliability of the invoicing process.

    Error Reduction and Efficiency Gains:

    By automating the invoicing process, the system reduced manual entry errors by an impressive 90%. The automation also cut down the time required to generate invoices by more than 50%, freeing up valuable time for the finance team to focus on higher-value tasks. Additionally, the system included error-checking mechanisms, such as data validation and conditional formatting, to flag any inconsistencies before the invoices were finalized.

    Scalability and Customization:

    The VBA-based system was designed with scalability in mind, capable of handling increasing volumes of invoices as the business grew. I also incorporated customizable templates, allowing the finance team to easily adjust the invoice format to meet specific client requirements or comply with different regulatory standards.

    Results:

    The implementation of the automated invoice generation system resulted in a more efficient and accurate invoicing process. The system’s ability to handle over 100 invoices per month with minimal manual intervention led to a significant reduction in processing time and errors, ultimately improving the company’s cash flow management and customer satisfaction.

    Visit original content creator repository
    https://github.com/Nakshnan/Automated-Invoice-System—VBA

  • PiggyAuctions

    PiggyAuctions Poggit-CI Discord

    PiggyAuctions is an open-sourced auction house plugin for PocketMine-MP allowing players to place auctions and bid on items.

    Why use PiggyAuctions over other competitors?

    1. BRAND LOYALTY!!! PiggyAuctions is a quality Piggy-flavored plugin refined throughout generations of the Sus genus. You won’t get to experience this authentic rich and savory flavor anywhere else. And, it’s free bacon, what else could you ask for?
    2. PiggyAuctions has bidding, searching, sorting, auto-refreshing, pagination, etc.
    3. Oink? You’re not going to install such an amazing plugin? ๐Ÿท
    4. Sloths are scary.

    Prerequisites

    • Basic knowledge on how to install plugins from Poggit Releases and/or Poggit CI
    • PMMP 4.0.0+
    • mysql & sqlite3 PHP extensions (should already exist within your PHP binaries)

    InvCrashFix is still needed!

    Supported Economy Providers

    Installation & Setup

    1. Install the plugin from Poggit.
    2. (Optional) Setup the data provider that PiggyAuctions will be using. By default, PiggyAuctions will use SQLite3 which requires no additional setup. If you would like to use MySQL instead, change database.type from sqlite to mysql & enter your MySQL credentials under database.mysql.
    3. (Optional) Setup your economy provider. If using EconomyAPI, this step can be skipped. Otherwise, change economy.provider to the name of the economy plugin being used, or xp for PMMP Player EXP.
    4. (Optional) Certain user inputs for creating and bidding on auctions can be configured. By default, the duration limit is 14 days, while bid & starting bid limit are the 32 bit integer max. We recommend not allowing values over the 32 bit integer max (2^31 or 2147483648).
    5. (Optional) You may configure messages in the message.yml file.
    6. You’re done! Start your server and begin auctioning items.

    Commands

    Command Description Permissions Aliases
    /auctionhouse Opens the auction house piggyauctions.command.auctionhouse /ah
    /auctionhouse [player] View a specific player’s auctions piggyauctions.command.auctionhouse /ah

    Permissions

    Permissions Description Default
    piggyauctions Allows usage of all PiggyAuctions features op
    piggyauctions.command Allow usage of all PiggyAuctions commands op
    piggyauctions.command.auctionhouse Allow usage of the /auctionhouse command true
    piggyauctions.limit.{NUMBER} Imposes a limit on amount of concurrent auctions for a player false

    Issue Reporting

    • If you experience an unexpected non-crash behavior with PiggyAuctions, click here.
    • If you experience a crash in PiggyAuctions, click here.
    • If you would like to suggest a feature to be added to PiggyAuctions, click here.
    • If you require support, please join our discord server here.
    • Do not file any issues related to outdated API version; we will resolve such issues as soon as possible.
    • We do not support any spoons of PocketMine-MP. Anything to do with spoons (Issues or PRs) will be ignored.
      • This includes plugins that modify PocketMine-MP’s behavior directly, such as TeaSpoon.

    License

       Copyright 2019 DaPigGuy
    
       Licensed under the Apache License, Version 2.0 (the "License");
       you may not use this file except in compliance with the License.
       You may obtain a copy of the License at
    
           http://www.apache.org/licenses/LICENSE-2.0
    
       Unless required by applicable law or agreed to in writing, software
       distributed under the License is distributed on an "AS IS" BASIS,
       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       See the License for the specific language governing permissions and
       limitations under the License.
    
    
    Visit original content creator repository https://github.com/DaPigGuy/PiggyAuctions
  • nha-kinh-lora-iot-thong-minh

    Nhร  kรญnh LoRa IOT thรดng minh

    Nhร  kรญnh LoRa IOT thรดng minh ฤ‘ฦฐแปฃc phรกt triแปƒn dแปฑa trรชn ESP8266, Arduino, LoRa

    Giแป›i thiแป‡u

    Hแป‡ thแป‘ng bao gแป“m 2 Node cรณ nhiแป‡m vแปฅ thu thแบญp dแปฏ liแป‡u sau ฤ‘รณ gแปญi vแป Gateway thรดng qua cรดng nghแป‡ LoRa. Dแปฏ liแป‡u nร y sแบฝ ฤ‘ฦฐแปฃc Gateway xแปญ lรฝ vร  ฤ‘แบฉy lรชn Website thรดng qua giao thแปฉc MQTT. Giao diแป‡n Website ฤ‘ฦฐแปฃc thiแบฟt kแบฟ vแป›i Blogger cho phรฉp giรกm sรกt cรกc thรดng sแป‘ แปŸ bแบฅt kแปณ nฦกi ฤ‘รขu mร  chรบng ta cรณ internet.

    Nhร  kรญnh LoRa IOT thรดng minh

    Tรญnh nฤƒng

    • Vแป›i IOT chรบng ta cรณ thแปƒ theo dรตi thiแบฟt bแป‹ แปŸ mแปi nฦกi miแป…n lร  cรณ internet
    • Vแป›i LoRa chรบng ta cรณ khoแบฃng cรกch truyแปn lรชn ฤ‘แบฟn hร ng kilomet
    • Giao diแป‡n Website trแปฑc quan, dแป… nhรฌn, tรชn miแปn blogspot miแป…n phรญ
    • Phรญm nhแบฅn cho phรฉp cร i ฤ‘แบทt WiFi cแปงa Gateway 1 cรกch dแป… dร ng
    • Mแบกch mแป™t lแป›p giรบp dแป… dร ng lร m thแปง cรดng, thรญch hแปฃp vแป›i sinh viรชn nghiรชn cแปฉu khoa hแปc

    Thรดng sแป‘ kแปน thuแบญt

    Node

    • ฤiแป‡n รกp vร o: 9-12VDC
    • Mร n hรฌnh hiแปƒn thแป‹: LCD1602
    • Socket cแบฃm biแบฟn: DHT11/DHT22/LM35/CB ฤแบฅt

    Gateway

    • ฤiแป‡n รกp vร o: 9-12VDC
    • Socket hiแปƒn thแป‹: LCD I2C
    Visit original content creator repository https://github.com/phatvu1294/nha-kinh-lora-iot-thong-minh
  • genai-from-basics-to-production

    GenAI: From Basics to Production

    Overview

    This repository is a comprehensive learning resource to guide you through developing Generative AI (GenAI) solutions.
    Starting from foundational concepts, you’ll progress to building scalable architectures for enterprise-level use cases like querying distributed domain knowledge.

    Examples of potential applications:

    • IT knowledge management
    • Product specifications for retailers
    • Internal employee portals

    By the end of this journey, you’ll have the skills and confidence to create robust Generative AI systems.


    Key Features

    • Beginner-Friendly: Start from the basics of Generative AI and build up to advanced topics.
    • Practical Notebooks: Hands-on exercises using Google Colaboratory.
    • Scalable Architectures: Learn to design solutions for real-world, enterprise-level challenges.
    • Customizable: Adapt the provided solutions to your specific use cases.

    Repository Structure

    โ”œโ”€โ”€ data/                     # Add your domain-specific datasets here.
    โ”œโ”€โ”€ notebooks/                # Step-by-step Google Colaboratory notebooks.
    โ”œโ”€โ”€ solutions/                # Completed versions of notebooks for reference.
    โ”œโ”€โ”€ README.md                 # Documentation for the repository.
    

    Requirements

    Technical Requirements

    • Laptop with Internet Access
    • Google Account (required for Google Colaboratory)

    If you donโ€™t have a Google account, create one for free:
    Create Google Account

    Tools Used

    • Google Colaboratory (Colab): A cloud-based tool to execute Python code seamlessly.

    Getting Started

    Clone the Repository

    git clone https://github.com/your-username/genai-from-basics-to-production.git
    cd genai-from-basics-to-production

    Set Up the Environment

    1. Open any notebook from the notebooks/ folder in Google Colaboratory.
    2. Add your datasets to the data/ folder or upload them directly to Colab as needed.

    Follow the Notebooks

    • Start with the introductory notebooks and progress to more advanced topics.
    • Each notebook includes clear explanations, practical code snippets, and exercises to deepen your understanding.

    Contributing

    We welcome contributions from the community!

    • If you have suggestions, enhancements, or bug fixes, feel free to open an issue or submit a pull request.

    License

    This project is licensed under the Apache 2.0 License. For more details, see the LICENSE file.


    Acknowledgments

    This project leverages Google Colaboratory and popular open-source libraries to provide an accessible, practical learning experience for everyone.

    Happy learning! ๐Ÿ˜Š

    โญ PS: Don’t forget to drop a star on this repo if you like it! โญ

    Visit original content creator repository
    https://github.com/kaushikmupadhya/genai-from-basics-to-production

  • goldsvet

    OSS Casino 2K25

    Formerly Goldsvet

    Web Casino Server Configuration Guide

    Official Telegram Community

    OSS Casino

    DEMO ย  | ย  TELEGRAM GROUP

    BEWARE OF ANY FORK/LINK THAT IMPERSONATES OUR OFFICIAL ACCOUNT @goldsvetcasino1 this not our GROUP anymore. The new group USERNAME is @osscasino.

    OSS Casino Latest 2025 release adds Laravel 10 and PHP 8.1+ support, Easy-Installer.

    OSS Casino1

    This code is just a preview. Contact admin on Telegram for the full version.

    Be cautios some old forks contain old group link that used by a scammer

    Currently, we provide the full source on my Telegram. There are approximately 1200 games totaling 45+ GB, including the latest Pragmatic games fixed & support mobile responsive.

    You can message me on Telegram for the full source code, including installation into your VPS/Dedicated Server.

    Multiple fixes and merged single database.

    Demo USER /Demo Play games have been added and activated. Added 100 games, bringing the total to 1200 games now.

    Server Setup Instructions

    1. Set up your server with the following components:

      • OS: Almalinux 8 / CentOS 7 recommended
      • Apache
      • MySQL
      • PHP 8.0+
      • Laravel 10
      • Node.js 16
      • PM2
      • Redis
    2. Enforce SSL for the domain.

    3. Extract/Clone this repo into the public_html folder.

    4. Enable PHP Extensions: Fileinfo, Imagick, Redis.

    5. Create a new email and set a password.

    6. Create a new database and grant full access.

    7. Import the SQL file db.sql from the directory.

    8. Ensure SSL is enforced for the domain.

    9. Run the following command in the terminal under the public_html folder:

        composer install
    1. Generate SSL CRT, KEY, and BUNDLE. Copy the contents of your CRT/KEY/BUNDLE to files in the /casino/PTwebsocket/ssl/ folder.

    2. For file uploads:

      • Additional Tip: Since it includes demo user accounts, generate a new password hash for existing users. Execute the following in phpMyAdmin (replace the hash). If you need to hash a new word, run this in phpMyAdmin:

    Minimal Installer

    Upload/Clone all files from this repo and run yourdomain.com/setup.php. It will help you handle the installation.

    SSL Instructions

    1. Delete any self-signed certificates.
    2. Generate or install the Let’s Encrypt certificate if available.
    3. Save the text file via notepad or directly as follows:
      • Certificate (CRT) ==> crt.crt
      • Private Key (KEY) ==> key.key
    4. Go to the folder PTWebSocket/ssl and replace those three files.
    5. Edit .env and /config/app.php (URL line 65) for domain, database, user/password, email, and password.

    File Edits

    Edit the / Socket File Changes in JSON files.

    PM2 Commands

    PM2 COMMANDS: PM2 Documentation

    SAMPLE USEFUL COMMANDS

    pm2 stop all
    pm2 delete all
    pm2 flush
    pm2 logs
    pm2 save

    FROM INSIDE PTWEBSOCKET web folder COMMANDS:

    pm2 start Arcade.js --watch
    pm2 start Server.js --watch
    pm2 start Slots.js --watch

    Allow Firewall Command

    Set your port for websocket then run these on terminal:

    firewall-cmd --zone=public --add-port=xxxx/tcp --permanent
    firewall-cmd --zone=public --add-port=xxxx/tcp --permanent
    firewall-cmd --zone=public --add-port=xxxx/tcp --permanent
    firewall-cmd --reload

    Interested or have a question?

    Contact me from the contact listed if you are interested in purchase/installation.

    Personal Telegram

    Telegram Group

    ย 

    BEWARE OF ANY FORK/LINK THAT IMPERSONATES OUR OFFICIAL ACCOUNT @goldsvetcasino1 this not our GROUP anymore. The new group official name is t.me/osscasino

    SCAMMER 1

    Visit original content creator repository https://github.com/zeusbyte/goldsvet
  • magic

    Where the Machine Creates the Code!

    Magic Cloud is a software development automation platform created and maintained by AINIRO.IO based upon AI, Low-Code, and No-Code. It’s based upon Hyperlambda, allowing you to dynamically create and orchestrate code, using meta programming and generative AI. Below is the Magic dashboard allowing you to automate most of the system using the built in AI agent using “vibe coding”.

    Vibe Coding with Magic

    The above is a screenshot of the integrated AI agent that allows you to.

    • Create and maintain your databases
    • Create and maintain APIs
    • Create and maintain AI agents, AI chatbots, and most things Magic can do

    CRUD generator

    In addition to its generative AI capabilities, Magic also comes with a CRUD generator, allowing you to point it at your database, click a button, and wrap all your tables into CRUD endpoints. Combined with its AI capabilities, this can sometimes save you 90% of your time when delivering backend APIs.

    CRUD generator

    No-Code AI

    Magic contains its own LLM that allows for generating Hyperlambda (backend) code using natural language. Combined with meta programming, this almost entirely eliminates the need to understand code and software development, yet still making it possible to create fairly complex systems using “vibe coding”, such as for instance AI agents with function calling, and custom ChatGPT “clones” using the AI Expert System.

    The concept is you provide a comment and description for what your Hyperlambda file should do. Then you click generate, and the LLM will automatically create code encapsulating your use case. Afterwards you can modify the code as you need. To pull this through, we actually fine tuned and created our own LLM model based upon OpenAI’s gpt-4.1-mini, which makes it extremely cost effective and fast.

    AI code generator

    Notice, at some point we’ll have to purely logically start charging for access to this LLM, since you’ll be using our tokens during inference, but for the time being the costs are so low that we’re paying them for you.

    Hyperlambda

    Hyperlambda is a “5th generation programming language”, that is on average 10 to 50 times less verbose than traditional languages such as C#, Java, Python, GoLang, and PHP. On average it can solve most problems with 5% of the codebase compared to any traditional programming language. This makes it an extremely high level programming language, allowing you to work declaratively instead of having to implement everything imperatively. Below is a simple HTTP CRUD Read endpoint implemented in C# and Hyperlambda to illustrate what effects this might have on your codebase.

    Hyperlambda versus C#

    The above C# code is 120 lines of code, divided into 9 different files. The Hyperlambda equivalent is 5 lines of code in one file. This declarative aspect of Hyperlambda makes you on average 20 times more productive, and reduces your technical debt by 95%.

    Hyperlambda has been officially recognised by Microsoft in several articles, and is currently being used by thousands of companies and individuals all over the world to solve software development backend problems. Hyperlambda is async to the bone, and have scalability and performance traits that’s almost on pair with C# and .Net 9.

    AI Agents

    The combination of meta programming and declarative constructs, in a homoiconic development environment, makes Hyperlambda extremely useful as a tool to create AI agents, sometimes allowing you to create highly complex AI agents, without having to write a single line of code yourself. You can see an example of this in the following video, where I create an AI agent that creates AI agents.

    Watch the video

    Components

    Magic is a complete software development platform, and contains among other things the following components.

    • Hyper IDE is a Low-Code and No-Code IDE with AI integrated into every aspect
    • SQL Studio allows you to execute SQL towards connected databases, in addition to visually designing your databases
    • Endpoint Generator allows you to rapidly generate CRUD endpoints and other types of endpoints that can be automatically generated somehow
    • Machine Learning allows you to create AI types with RAG data, and even AI agents allowing you to integrate the LLM into your business apps
    • Endpoint browser is Magic’s own version of Swagger, allowing you to browse and test your HTTP endpoints
    • Users & Roles Management allows you to manage users and roles in an RBAC-based access control system
    • Task Manager allows you to create and persist Hyperlambda tasks, in addition to scheduling these to execute in the future at a specific date, or according to a repetition pattern
    • Plugins allows you to install plugins such as NetSuite integrations, HubSpot integrations, etc
    • Audit Log allows you to see your cloudlet’s log
    • Hyperlambda Playground allows you to execute Hyperlambda in immediate mode to perform some task or test a piece of code
    • Database Administration allows you to connect to any MySQL, PostgreSQL, or Microsoft SQL Server database – In addition to also creating SQLite databases as you see fit
    • Configuration allows you to manage your server’s configuration
    • Chatbot Wizard allows you to create AI chatbots based upon RAG by scraping a website and embedding a simple JavaScript file into your website

    Combined, the above components allows you to rapidly manage your application(s) from an extremely high level, giving you clarity and control over your application. The project is being actively maintained by AINIRO, specifically Thomas Hansen, and has been actively maintained for more than 6 years. The project is particularly useful for anything related to AI, but is also a “general purpose backend development environment”. For more information about Magic, please refer to its documentation below.

    Getting Started

    Clone the repository, and make sure youโ€™ve got .Net Core version 9 installed, the latest version of NodeJS, and Angular, and enter the “backend” and “frontend” folders with two terminals, and execute the following commands in the respective terminals.

    1. Backend folder dotnet run
    2. Frontend folder ng serve

    After some few minutes you should be able to access the dashboard from localhost:4200, and login to your cloudlet using http://localhost:5000 as your backend URL. The intial username and password combination is the same; “root” and “root”. Once logged in, you have to provide a root password and your email address. Once this is done, you can start using your cloudlet.

    If you want to play with the AI capabilities of Magic, you’ll have to configure your cloudlet with an OpenAI API key – You can do this from for instance the Misc/Configuration parts of your dashboard. You can also use Docker if you wish, and if this sounds like too much hassle, we can help you with a managed cloudlet.

    NOTICE – I’ve only got Linux and OSX builds of the VSS plugin for SQLite, so all the AI features will only work on OSx (Mx CPU) or Linux.

    License

    This project, and all of its satellite project, is licensed under the terms of the MIT license, as published by the Open Source Initiative. See LICENSE file for details. For licensing inquiries you can contact Thomas Hansen thomas@ainiro.io

    Copyright and maintenance

    The projects is copyright of Thomas Hansen 2019 – 2025, and professionally maintained by AINIRO.IO.

    Visit original content creator repository https://github.com/polterguy/magic
  • moodist

    Moodist Logo Banner

    Moodist ๐ŸŒฒ

    Ambient sounds for focus and calm.

    Visit Moodist | Buy Me a Coffee

    Table of Contents

    Features

    1. ๐ŸŽต Over 75 ambient sounds.
    2. ๐Ÿ“ Persistent sound selection.
    3. โœˆ๏ธ Sharing sound selections with others.
    4. ๐Ÿงฐ Custom sound presets.
    5. ๐ŸŒ™ Sleep timer for sounds.
    6. ๐Ÿ““ Notepad for quick notes.
    7. ๐Ÿ… Pomodoro timer.
    8. โœ… Simple to-do list (soon).
    9. โฏ๏ธ Media controls.
    10. โŒจ๏ธ Keyboard shortcuts for everything.
    11. ๐Ÿฅท Privacy focused: no data collection.
    12. ๐Ÿ’ฐ Completely free, open-source, and self-hostable.

    Tools

    • โšก TypeScript: Programming Language
    • ๐Ÿ”จ React: UI Library
    • ๐Ÿง‘โ€๐Ÿš€ Astro: Meta Framework
    • ๐ŸŽจ CSS Modules: Styling
    • ๐Ÿป Zustand: State Management
    • ๐ŸŽญ Framer Motion: Animation Library
    • โš™๏ธ Radix: Accessible Components
    • ๐Ÿ“• Storybook: Component Documentation
    • ๐Ÿงช Vitest: Unit Testing (soon)
    • ๐Ÿ”ญ Playwright: End-To-End Testing (soon)
    • ๐Ÿ” ESLint: Code Linting
    • ๐Ÿงน Prettier: Code Formatting
    • ๐Ÿงผ Stylelint: CSS Linting
    • ๐Ÿถ Husky: Git Hooks
    • ๐Ÿ“ Lint Staged: Running Linters on Staged Files
    • ๐Ÿงฝ Commitlint: Git Commit Linting
    • ๐Ÿงญ Commitizen: Git Commit Message Helper
    • ๐Ÿ““ Standard Version: Versioning and CHANGLOG Generation
    • ๐Ÿงฐ PostCSS: CSS Transformations

    Commands

    • npm run dev: run development server
    • npm run build: build for production
    • npm run preview: preview the built app
    • npm run lint: lint files using ESLint
    • npm run lint:fix: lint and fix using ESLint
    • npm run lint:style: lint styles using Stylelint
    • npm run lint:style:fix: lint and fix styles using Stylelint
    • npm run format: format files using Prettier
    • npm run commit: commit message using Commitizen
    • npm run release:major: release major version
    • npm run release:minor: release minor version
    • npm run release:patch: release patch version
    • npm run storybook: run Storybook

    Contributing

    ๐Ÿšง Please check CONTRIBUTING.md file.

    Support Moodist

    โญ Give a star if you liked this project.

    โ˜• Buy Me a Coffee to help me maintain Moodist.

    License

    This project is licensed under the MIT License – see the LICENSE file for details.

    โš ๏ธ Third-Party Assets

    Some sounds used in this project are sourced from third-party providers and are subject to different licenses:

    Visit original content creator repository https://github.com/remvze/moodist