[
  {
    "path": ".gitignore",
    "content": "*.jks\n*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.idea/\n/.tags\n/.tags1\n/script/node/watch/node_modules/\n/keystore.jks\n/.vscode/\n/.settings/\n/sample/.settings/\n/app/.settings/\n/app/build/\n.project\napp/.classpath\napp/.project\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under androlua.common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "PluginDev.md",
    "content": "# 氢应用插件开发\n\n## 插件介绍\n插件用 lua 语言开发，所以需要能看懂 lua，插件基于 androlua 框架下，\n氢应用插件结构很简单，每个插件放在手机的 sdcard/Android/data/pub.hydrogen.android/files/LLLLLua 目录下\n\n1. 首先在上面的目录下创建插件文件夹\n2. 编写插件主程序，插件**至少**包含2文件:\n`info.json` 插件描述文件，`main.lua` 插件启动文件，接下来分别介绍：\n\n## 插件结构\n首先是 `info.json`\n```\n{\n  \"id\": \"pub.hanks.gacha\",\n  \"name\": \"网易插画\",\n  \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fhaaa8qcofj2046046we9.jpg\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0\",\n  \"versionCode\": 1,\n  \"desc\": \"网易每日插画排行\"\n}\n```\n\nid: 插件唯一标识符号\nname: 插件名称\nicon: 插件图标\nmain: 插件启动文件, 可以自定义名称\nversionName: 插件版本名称\nversionVersion: 插件版本号\ndesc: 插件描述\n\n然后是启动文件（main.lua），也就是主程序，以`网易插画`的代码为例:\n\n```lua\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.StaggeredGridLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"java.util.Calendar\"\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\n\n-- 上面是需要导入用到的 class 类以及引用的 so 或 lua\n\n\nlocal calender = Calendar.getInstance()\nlocal max\nlocal data = {}\nlocal adapter\nlocal imageWidth = uihelper.getScreenWidth() / 2\n\n-- 布局文件\nlocal layout = {\n    RecyclerView,\n    id = \"recyclerView\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"200dp\",\n        scaleType = \"fitXY\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_gravity = \"right\",\n        background = \"#88000000\",\n        paddingLeft = \"6dp\",\n        paddingRight = \"6dp\",\n        paddingTop = \"2dp\",\n        paddingBottom = \"2dp\",\n        textSize = \"10sp\",\n        visibility = 'gone',\n        textColor = \"#aaffffff\",\n    },\n    {\n        View,\n        id = \"layer\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        background = \"@drawable/layout_selector_tran\",\n        clickable = true,\n    },\n}\n\n\nlocal function fetchData()\n\n    -- 获取数据\n    local year = calender.get(Calendar.YEAR)\n    local month = calender.get(Calendar.MONTH) + 1\n    local day = calender.get(Calendar.DAY_OF_MONTH)\n\n    local markFrom = string.format('%04d-%02d-%02d', year, month, day)\n    calender.add(Calendar.DAY_OF_MONTH, -1)\n    year = calender.get(Calendar.YEAR)\n    month = calender.get(Calendar.MONTH) + 1\n    day = calender.get(Calendar.DAY_OF_MONTH)\n    local mark = string.format('%04d-%02d-%02d', year, month, day)\n\n    local url = string.format(\"http://gacha.163.com/api/v1/ranking/pic?type=0&mark=%s&fromMark=%s\", mark, markFrom)\n    -- 发起请求\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local json = JSON.decode(body)\n        local html = json.result.rankingHtml\n        -- 异步回调\n        uihelper.runOnUiThread(activity, function()\n            -- UI 线程执行\n            local s = #data\n            for w, h, url in string.gmatch(html, 'data[-]width=\"([0-9]+)\" data[-]height=\"([0-9]+)\".-data[-]src=\"(.-)\"') do\n                local item = { url = url, w = w, h = h }\n                local id, type = string.match(item.url, 'http://gacha[.]nosdn[.]127[.]net/([0-9a-z]+)[.]([a-z]+)')\n                item.id = id\n                item.type = type\n                item.fullUrl = string.format('http://gacha.nosdn.127.net/%s.%s', id, type)\n                item.calcHeight = math.floor(imageWidth * tonumber(item.h) / tonumber(item.w))\n                data[#data + 1] = item\n            end\n            adapter.notifyItemRangeChanged(s, #data)\n        end)\n    end)\nend\n\nlocal function launchDetail(item)\n    local args = { uris = { item.fullUrl } }\n    PicturePreviewActivity.start(activity, JSON.encode(args))\nend\n\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000) -- 设置状态栏颜色\n    activity.setContentView(loadlayout(layout)) -- 设置布局\n    -- 创建Adapter\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.getLayoutParams().width = imageWidth\n            holder.itemView.setTag(views)\n            views.layer.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1\n                launchDetail(data[position])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            views.iv_image.getLayoutParams().height = item.calcHeight\n            LuaImageLoader.load(views.iv_image, item.url)\n            if position == #data then fetchData() end\n        end,\n    }))\n    recyclerView.setLayoutManager(StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL))\n    recyclerView.setAdapter(adapter)\n    fetchData()\nend\n```\n\n插件开发完毕\n\n\n### 参考链接\n[AndroLua_pro](https://github.com/nirenr/AndroLua_pro)\n[lua语法](http://www.runoob.com/lua/lua-basic-syntax.html)\n[lua的手册](https://cloudwu.github.io/lua53doc/manual.html)\n[Android文档](https://developer.android.com/develop/index.html?hl=zh-cn)\n\n\n\n"
  },
  {
    "path": "README.md",
    "content": "# hydrogenApp\n\nhydrogen is a **pluggable** android app, use `Lua` develop android, minSdkVersion=\"15\", lua 5.3\nplugin wrote by `lua` program language\n\n[APK Download](https://www.coolapk.com/apk/pub.hydrogen.android)\n\n<img src=\"http://ww1.sinaimg.cn/large/8c9b876fly1fxadl4x1lfj20780780sk.jpg\"/>\n\n## App Plugin\n\n![](http://image.coolapk.com/apk_image/2017/0706/1-for-148937-o_1bkb0ue7m16mp165il5srd41ei815-uid-518407.jpg.t.jpg)\n![](http://image.coolapk.com/apk_image/2017/0706/2-for-148937-o_1bkb0ue7n1h1p1ke3ssuj4q1dab16-uid-518407.jpg.t.jpg)\n![](http://image.coolapk.com/apk_image/2017/0706/3-for-148937-o_1bkb0ue7n1sn1nc01k8b17bk3h017-uid-518407.jpg.t.jpg)\n![](http://image.coolapk.com/apk_image/2017/0706/4-for-148937-o_1bkb0ue7natj1uk010qm1kbgdq218-uid-518407.jpg.t.jpg)\n![](http://image.coolapk.com/apk_image/2017/0901/S70901-173605-for-148937-o_1boucs1494kp1qo81qul1656ei9q-uid-518407.jpg.t.jpg)\n![](http://image.coolapk.com/apk_image/2017/0901/S70901-173626-for-148937-o_1boucsbvrkcu1omqrte5d8amc10-uid-518407.jpg.t.jpg)\n![](http://image.coolapk.com/apk_image/2017/0901/S70901-173652-for-148937-o_1boucsgnk6rlsvn1j9f1q8177n16-uid-518407.jpg.t.jpg)\n![](http://image.coolapk.com/apk_image/2017/0901/S70901-173716-for-148937-o_1boucsl56mdt10am1vgsqs099m1c-uid-518407.jpg.t.jpg)\n\n\n## 项目结构\n\n宿主：`sample`  \n宿主用到的 lua 文件： `lua_main`  \n\n插件目录：`lua`  \n脚本：script  \n\n\n### 插件开发步骤\n\n插件目录：lua  \n插件包含文件 `info.json` `main.lua`\n\n```\n{\n  \"id\": \"pub.hanks.gacha\",\n  \"name\": \"网易插画\",\n  \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fhaaa8qcofj2046046we9.jpg\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0\",\n  \"versionCode\": 1,\n  \"desc\": \"网易每日插画排行\"\n}\n\nid: 插件唯一标识符号\nname: 插件名称\nicon: 插件图标\nmain: 插件启动文件\nversionName: 插件版本名称\nversionVersion: 插件版本号\ndesc: 插件描述\n```\n\n### 插件发布\n\n插件生成目录 api_luanroid, 执行 java 单元测试 `zipPlugin`， 该方法会打包好插件并更新获取插件的 api, 成功后，然后 push 到线上\n\n[lua语法](http://www.runoob.com/lua/lua-basic-syntax.html)\n[lua的手册](https://cloudwu.github.io/lua53doc/manual.html)\n\n```\n\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.view.*\"\nimport \"android.app.*\"\nimport \"android.net.*\"\nimport \"android.content.*\"\n\n```\n\n\n### 更新每日壁纸\n\nhttps://coding.net/u/zhangyuhan/p/api_luanroid/git/blob/master/api/splash\n\n### 版本更新\n\nhttps://coding.net/u/zhangyuhan/p/api_luanroid/git/blob/master/api/update\n\n\n## 插件开发\n\n请看[插件开发指南](https://github.com/hanks-zyh/hydrogenApp/blob/master/PluginDev.md)，更多的功能使用可以参考已有的[插件列表](https://github.com/hanks-zyh/hydrogenApp/tree/master/lua)，目录为 lua 目录\n\n\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options androlua.common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n        google()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.2.1'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n        google()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Fri Nov 16 10:45:13 CST 2018\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-4.6-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "hydrogen-library/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "hydrogen-library/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 28\n    defaultConfig {\n        minSdkVersion 16\n        targetSdkVersion 28\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n        vectorDrawables.useSupportLibrary = true\n    }\n    signingConfigs {\n        release {\n            keyAlias 'luajandroid'\n            keyPassword 'CeRRV5eG'\n            storeFile file('../keystore/luajandroid_keystore.jks')\n            storePassword 'CeRRV5eG'\n        }\n    }\n    buildTypes {\n        release {\n            minifyEnabled true\n            zipAlignEnabled true\n            signingConfig signingConfigs.release\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n        preRelease {\n            debuggable true\n            signingConfig signingConfigs.release\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    sourceSets {\n        main {\n            jniLibs.srcDirs = ['libs']\n        }\n    }\n    productFlavors {\n    }\n}\n\nrepositories {\n    flatDir {\n        dirs 'libs'\n    }\n}\n\ndef support_version = '28.0.0'\ndependencies {\n    // test\n    androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {\n        exclude group: 'com.android.support', module: 'support-annotations'\n    })\n    // local\n    implementation fileTree(include: ['*.jar'], dir: 'libs')\n    testImplementation 'junit:junit:4.12'\n    // remote\n    implementation \"com.android.support:appcompat-v7:$support_version\"\n    implementation \"com.android.support:design:$support_version\"\n    implementation 'com.github.bumptech.glide:glide:3.7.0'\n    implementation 'cn.jzvd:jiaozivideoplayer:6.2.3'\n    implementation 'com.squareup.okhttp3:okhttp:3.10.0'\n    implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'\n    implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.7.2'\n    implementation 'jp.wasabeef:glide-transformations:2.0.2'\n}\n"
  },
  {
    "path": "hydrogen-library/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:\\android-sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n\n-keep class android.**{*;}\n-keep class androlua.**{*;}\n-keep class com.**{*;}\n-keep class androlua.common.**{*;}\n-keep class pub.**{*;}\n\n# Glide\n-keep public class * implements com.bumptech.glide.module.GlideModule\n-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {\n  **[] $VALUES;\n  public *;\n}\n\n# Okhttp\n-dontwarn okio.**\n-dontwarn javax.annotation.Nullable\n-dontwarn javax.annotation.ParametersAreNonnullByDefault\n"
  },
  {
    "path": "hydrogen-library/src/androidTest/java/pub/hanks/luajandroid/ExampleInstrumentedTest.java",
    "content": "package pub.hanks.luajandroid;\n\nimport android.animation.LayoutTransition;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.res.ColorStateList;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Paint;\nimport android.graphics.drawable.ColorDrawable;\nimport android.graphics.drawable.GradientDrawable;\nimport android.os.Build;\nimport android.support.annotation.NonNull;\nimport android.support.design.widget.AppBarLayout;\nimport android.support.design.widget.BottomNavigationView;\nimport android.support.design.widget.BottomSheetBehavior;\nimport android.support.design.widget.CollapsingToolbarLayout;\nimport android.support.design.widget.CoordinatorLayout;\nimport android.support.design.widget.TabLayout;\nimport android.support.graphics.drawable.VectorDrawableCompat;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\nimport android.support.v7.app.AlertDialog;\nimport android.support.v7.widget.GridLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.Toolbar;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.webkit.WebChromeClient;\nimport android.webkit.WebView;\nimport android.widget.AdapterView;\nimport android.widget.BaseAdapter;\nimport android.widget.GridView;\nimport android.widget.HorizontalScrollView;\nimport android.widget.LinearLayout;\nimport android.widget.ListView;\nimport android.widget.RadioButton;\nimport android.widget.RadioGroup;\nimport android.widget.TextView;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport java.io.File;\nimport java.net.URI;\n\nimport static junit.framework.Assert.assertEquals;\n\n/**\n * Instrumentation test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        new ColorDrawable(0xff);\n\n        LinearLayout linearLayout = new LinearLayout(appContext);\n        linearLayout.setOrientation(LinearLayout.VERTICAL);\n        assertEquals(\"pub.hanks.luajandroid\", appContext.getPackageName());\n        linearLayout.animate().scaleX(2).scaleY(2).translationX(100).setDuration(3000).start();\n        VectorDrawableCompat.createFromPath(\"\");\n\n        linearLayout.setClickable(true);\n        linearLayout.setFocusable(true);\n        linearLayout.setFocusableInTouchMode(true);\n        linearLayout.setBackgroundResource(R.drawable.layout_selector_tran);\n\n        Intent intent = new Intent();\n        new File(new URI(intent.getData().getPath())).getAbsolutePath();\n\n        RecyclerView recyclerView = new RecyclerView(appContext);\n        recyclerView.setVerticalFadingEdgeEnabled(false);\n\n        GridView gridLayout = new GridView(appContext);\n        gridLayout.setNumColumns(5);\n        gridLayout.setStretchMode(GridView.STRETCH_SPACING);\n        gridLayout.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            @Override\n            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n\n            }\n        });\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            gridLayout.setElevation(20);\n        }\n        gridLayout.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n\n            }\n        }, 1000);\n\n        BottomSheetBehavior<RecyclerView> sheetBehavior = BottomSheetBehavior.from(recyclerView);\n        if (sheetBehavior.getState() != BottomSheetBehavior.STATE_COLLAPSED) {\n            sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);\n        }\n\n        new GridLayoutManager(appContext, 3);\n\n        HorizontalScrollView horizontalScrollView = new HorizontalScrollView(appContext);\n        horizontalScrollView.setHorizontalScrollBarEnabled(false);\n        ListView listView = new ListView(appContext);\n        listView.setDividerHeight(0);\n        TextView textView = new TextView(appContext);\n        textView.setMaxLines(1);\n        textView.setSingleLine(true);\n        TabLayout tabLayout = new TabLayout(appContext);\n        tabLayout.setVisibility(View.VISIBLE);\n        WebView webView = new WebView(appContext);\n        webView.setWebChromeClient(new WebChromeClient());\n        //webView.addJavascriptInterface(this, \"\");\n        Bitmap bitmap = BitmapFactory.decodeResource(appContext.getResources(), R.id.et_url);\n        tabLayout.setLayoutTransition(new LayoutTransition());\n        final BottomNavigationView bottomView = new BottomNavigationView(appContext);\n        ColorStateList textColor = ColorStateList.valueOf(0xFFFF0000);\n        bottomView.setItemTextColor(textColor);\n        bottomView.getMenu().add(\"\");\n        bottomView.getMenu().add(\"\");\n        bottomView.getMenu().add(\"\");\n        bottomView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {\n            @Override\n            public boolean onNavigationItemSelected(@NonNull MenuItem item) {\n                item.getTitle();\n                item.setChecked(true);\n                return true;\n            }\n        });\n\n        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);\n\n        new AlertDialog.Builder(appContext)\n                .setItems(new String[]{}, new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n\n                    }\n                })\n                .setSingleChoiceItems(new String[]{}, 0, new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n\n                    }\n                })\n                .show();\n        RadioGroup radioGroup = new RadioGroup(appContext);\n        RadioButton radioButton = new RadioButton(appContext);\n        radioGroup.addView(radioButton);\n\n\n        new Toolbar(appContext).setNavigationOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n\n            }\n        });\n        GradientDrawable drawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{});\n\n\n        CollapsingToolbarLayout collapsingToolbarLayout = new CollapsingToolbarLayout(appContext);\n        CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();\n        params.setBehavior(new AppBarLayout.ScrollingViewBehavior());\n\n\n        new AlertDialog.Builder(appContext).setTitle(\"\").setMessage(\"\")\n                .setPositiveButton(\"取消\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n\n                    }\n                })\n        .show();\n\n        GradientDrawable gd = new GradientDrawable();\n        gd.setShape(GradientDrawable.OVAL);\n        gd.setColor(0xFFFFFFFF);\n        // 动态代理\n\n\n\n\n\n    }\n\n    class MyAdapter extends BaseAdapter {\n\n        @Override\n        public int getCount() {\n            return 0;\n        }\n\n        @Override\n        public Object getItem(int position) {\n            return null;\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return 0;\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"pub.hanks.luajandroid\">\n\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:label=\"@string/app_name\"\n        android:resizeableActivity=\"true\">\n        <activity\n            android:theme=\"@style/AppTheme\"\n            android:name=\"androlua.LuaActivity\"\n            android:exported=\"true\"\n            android:screenOrientation=\"user\"\n            android:supportsPictureInPicture=\"true\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n            </intent-filter>\n        </activity>\n        <activity android:name=\"androlua.widget.picture.PicturePreviewActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data\n                    android:host=\"pub.hydrogen.android\"\n                    android:scheme=\"hydrogen\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\"androlua.widget.webview.WebViewActivity\"\n            android:hardwareAccelerated=\"true\" />\n        <activity\n            android:name=\"androlua.widget.video.VideoPlayerActivity\"\n            android:configChanges=\"orientation|screenSize|keyboardHidden\"\n            android:screenOrientation=\"portrait\" />\n\n        <meta-data\n            android:name=\"androlua.widget.glide.LuaGlideModule\"\n            android:value=\"GlideModule\" />\n    </application>\n</manifest>"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaActivity.java",
    "content": "package androlua;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Message;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.widget.DrawerLayout;\nimport android.view.ContextMenu;\nimport android.view.Gravity;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.ViewGroup.LayoutParams;\nimport android.widget.FrameLayout;\nimport android.widget.ScrollView;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.luajava.JavaFunction;\nimport com.luajava.LuaException;\nimport com.luajava.LuaObject;\nimport com.luajava.LuaState;\nimport com.luajava.LuaStateFactory;\n\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.HashMap;\n\nimport androlua.base.BaseActivity;\nimport androlua.common.LuaLog;\nimport androlua.fragment.MenuFragment;\nimport pub.hanks.luajandroid.R;\n\npublic class LuaActivity extends BaseActivity implements LuaContext {\n\n    public Handler handler;\n    public TextView status;\n    private LuaState L;\n    private ScrollView errorLayout;\n    private LuaObject mOnKeyDown;\n    private LuaObject mOnKeyUp;\n    private LuaObject mOnKeyLongPress;\n    private LuaObject mOnTouchEvent;\n    private LuaDexLoader luaDexLoader;\n    private LuaManager luaManager;\n    private FrameLayout main;\n    private MenuFragment menuFragment;\n    private DrawerLayout layout_drawer;\n\n    public static void start(Context context, String luaPath) {\n        Intent starter = new Intent(context, LuaActivity.class);\n        starter.putExtra(\"luaPath\", luaPath);\n        context.startActivity(starter);\n    }\n\n    public void setContentView(View view) {\n        main.removeAllViews();\n        main.addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));\n\n        FragmentManager fragmentManager = getSupportFragmentManager();\n        if (fragmentManager.findFragmentByTag(\"menu\") == null) {\n            fragmentManager.beginTransaction()\n                    .replace(R.id.menu, menuFragment, \"menu\").commitAllowingStateLoss();\n        }\n    }\n\n    public void closeDrawer() {\n        if (layout_drawer == null) {\n            return;\n        }\n        layout_drawer.closeDrawer(Gravity.RIGHT);\n    }\n\n\n    @Override\n    public void setContentView(View view, LayoutParams params) {\n        super.setContentView(view, params);\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_lua);\n        main = (FrameLayout) findViewById(R.id.main);\n        layout_drawer = (DrawerLayout) findViewById(R.id.layout_drawer);\n        menuFragment = MenuFragment.newInstance();\n        handler = new MainHandler(this);\n\n        // 用于出错时显示\n        initErrorLayout();\n\n        initLua(savedInstanceState);\n    }\n\n    public void disableDrawer(){\n        if (layout_drawer == null) {\n            return;\n        }\n        layout_drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);\n    }\n\n    private void initLua(Bundle savedInstanceState) {\n        try {\n            Object[] arg = LuaUtil.IntentHelper.getArgs(getIntent());\n            luaManager = LuaManager.getInstance();\n            String luaFile = LuaUtil.IntentHelper.getLuaPath(getIntent());\n\n            L = LuaStateFactory.newLuaState();\n            L.openLibs();\n\n            L.pushJavaObject(this);\n            L.setGlobal(\"activity\");\n\n            L.getGlobal(\"activity\");\n            L.setGlobal(\"this\");\n\n            L.pushContext(this);\n            L.getGlobal(\"luajava\");\n\n            L.pushString(luaManager.getLuaExtDir());\n            L.setField(-2, \"luaextdir\");\n\n            L.pushString(luaManager.getLuaDir());\n            L.setField(-2, \"luadir\");\n\n\n            L.pushString(luaManager.getLuaLpath());\n            L.setField(-2, \"luapath\");\n\n            L.pop(1);\n\n            JavaFunction print = new LuaPrint(L);\n            print.register(\"print\");\n\n            L.getGlobal(\"package\");\n            L.pushString(luaManager.getLuaLpath());\n            L.setField(-2, \"path\");\n            L.pushString(luaManager.getLuaCpath());\n            L.setField(-2, \"cpath\");\n            L.pop(1);\n\n\n            mOnKeyDown = L.getLuaObject(\"onKeyDown\");\n            if (mOnKeyDown.isNil())\n                mOnKeyDown = null;\n            mOnKeyUp = L.getLuaObject(\"onKeyUp\");\n            if (mOnKeyUp.isNil())\n                mOnKeyUp = null;\n            mOnKeyLongPress = L.getLuaObject(\"onKeyLongPress\");\n            if (mOnKeyLongPress.isNil())\n                mOnKeyLongPress = null;\n            mOnTouchEvent = L.getLuaObject(\"onTouchEvent\");\n            if (mOnTouchEvent.isNil())\n                mOnTouchEvent = null;\n\n            luaDexLoader = new LuaDexLoader();\n            luaDexLoader.loadLibs();\n            if (!luaFile.startsWith(\"/\")) {\n                luaFile = luaManager.getLuaExtDir() + \"/\" + luaFile;\n            }\n            luaManager.doFile(L, luaFile, arg);\n            luaManager.runFunc(L, \"onCreate\", savedInstanceState);\n        } catch (Exception e) {\n            sendMsg(e.getMessage());\n            setContentView(this.errorLayout);\n        }\n    }\n\n    private void initErrorLayout() {\n        errorLayout = new ScrollView(this);\n        errorLayout.setFillViewport(true);\n        errorLayout.setBackgroundColor(Color.WHITE);\n\n        status = new TextView(this);\n        status.setPadding(10, 100, 10, 0);\n        status.setTextColor(Color.BLACK);\n        status.setText(\"\");\n        status.setTextIsSelectable(true);\n\n        errorLayout.addView(status, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));\n    }\n\n    public ArrayList<ClassLoader> getClassLoaders() {\n        return luaDexLoader.getClassLoaders();\n    }\n\n    public HashMap<String, String> getLibrarys() {\n        return luaDexLoader.getLibrarys();\n    }\n\n    public void loadResources(String path) {\n        luaDexLoader.loadResources(path);\n    }\n\n    public LuaState getLuaState() {\n        return L;\n    }\n\n    @Override\n    protected void onStart() {\n        super.onStart();\n        luaManager.runFunc(L, \"onStart\");\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        luaManager.runFunc(L, \"onResume\");\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        luaManager.runFunc(L, \"onPause\");\n    }\n\n    @Override\n    protected void onStop() {\n        super.onStop();\n        luaManager.runFunc(L, \"onStop\");\n    }\n\n    @Override\n    protected void onNewIntent(Intent intent) {\n        luaManager.runFunc(L, \"onNewIntent\", intent);\n        super.onNewIntent(intent);\n    }\n\n    @Override\n    protected void onDestroy() {\n        try {\n            luaManager.runFunc(L, \"onDestroy\");\n            super.onDestroy();\n//            L.close();\n            L.gc(LuaState.LUA_GCCOLLECT, 1);\n            System.gc();\n        } catch (Exception e) {\n            LuaLog.e(e);\n        }\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        luaManager.runFunc(L, \"onActivityResult\", requestCode, resultCode, data);\n        super.onActivityResult(requestCode, resultCode, data);\n    }\n\n    @Override\n    public void onBackPressed() {\n        Object ret = luaManager.runFunc(L, \"onBackPressed\");\n        if (ret != null && ret.getClass() == Boolean.class && (Boolean) ret) {\n            return;\n        }\n        super.onBackPressed();\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (mOnKeyDown != null) {\n            try {\n                Object ret = mOnKeyDown.call(keyCode, event);\n                if (ret != null && ret.getClass() == Boolean.class && (Boolean) ret)\n                    return true;\n            } catch (LuaException e) {\n                sendMsg(\"onKeyDown \" + e.getMessage());\n            }\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public boolean onKeyUp(int keyCode, KeyEvent event) {\n        if (mOnKeyUp != null) {\n            try {\n                Object ret = mOnKeyUp.call(keyCode, event);\n                if (ret != null && ret.getClass() == Boolean.class && (Boolean) ret)\n                    return true;\n            } catch (LuaException e) {\n                sendMsg(\"onKeyUp \" + e.getMessage());\n            }\n        }\n        return super.onKeyUp(keyCode, event);\n    }\n\n    @Override\n    public boolean onKeyLongPress(int keyCode, KeyEvent event) {\n        if (mOnKeyLongPress != null) {\n            try {\n                Object ret = mOnKeyLongPress.call(keyCode, event);\n                if (ret != null && ret.getClass() == Boolean.class && (Boolean) ret)\n                    return true;\n            } catch (LuaException e) {\n                sendMsg(\"onKeyLongPress \" + e.getMessage());\n            }\n        }\n        return super.onKeyLongPress(keyCode, event);\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent event) {\n        if (mOnTouchEvent != null) {\n            try {\n                Object ret = mOnTouchEvent.call(event);\n                if (ret != null && ret.getClass() == Boolean.class && (Boolean) ret)\n                    return true;\n            } catch (LuaException e) {\n                sendMsg(\"onTouchEvent \" + e.getMessage());\n            }\n        }\n        return super.onTouchEvent(event);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        luaManager.runFunc(L, \"onCreateOptionsMenu\", menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        Object ret = null;\n        if (!item.hasSubMenu())\n            ret = luaManager.runFunc(L, \"onOptionsItemSelected\", item);\n        if (ret != null && ret.getClass() == Boolean.class && (Boolean) ret)\n            return true;\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {\n        luaManager.runFunc(L, \"onCreateContextMenu\", menu, v, menuInfo);\n        super.onCreateContextMenu(menu, v, menuInfo);\n    }\n\n    @Override\n    public boolean onContextItemSelected(MenuItem item) {\n        luaManager.runFunc(L, \"onContextItemSelected\", item);\n        return super.onContextItemSelected(item);\n    }\n\n    public int getWidth() {\n        return getResources().getDisplayMetrics().widthPixels;\n    }\n\n    public int getHeight() {\n        return getResources().getDisplayMetrics().heightPixels;\n    }\n\n    public void toast(String msg) {\n        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();\n    }\n\n\n    //显示信息\n    public void sendMsg(String msg) {\n        Message message = new Message();\n        Bundle bundle = new Bundle();\n        bundle.putString(\"data\", msg);\n        message.setData(bundle);\n        message.what = 0;\n        handler.sendMessage(message);\n        LuaLog.e(msg);\n    }\n\n\n    // avoid handler leak memory\n    private static class MainHandler extends Handler {\n        WeakReference<Activity> activityWeakReference;\n\n        private MainHandler(Activity activity) {\n            activityWeakReference = new WeakReference<>(activity);\n        }\n\n        @Override\n        public void handleMessage(Message msg) {\n            super.handleMessage(msg);\n            Activity activity = activityWeakReference.get();\n            if (activity == null || !(activity instanceof LuaActivity)) {\n                return;\n            }\n            LuaActivity luaActivity = (LuaActivity) activity;\n            switch (msg.what) {\n                case 0: {\n                    String data = msg.getData().getString(\"data\");\n                    luaActivity.toast(data);\n                    luaActivity.status.append(data + \"\\n\");\n                    luaActivity.setContentView(luaActivity.errorLayout);\n                }\n                break;\n                //                case 1: {\n                //                    Bundle data = msg.getData();\n                //                    luaActivity.setField(data.getString(\"data\"), ((Object[]) data.getSerializable(\"args\"))[0]);\n                //                }\n                //                break;\n                //                case 2: {\n                //                    String src = msg.getData().getString(\"data\");\n                //                    luaActivity.luaManager.runFunc(L, src);\n                //                }\n                //                break;\n                //                case 3: {\n                //                    String src = msg.getData().getString(\"data\");\n                //                    Serializable args = msg.getData().getSerializable(\"args\");\n                //                    luaActivity.luaManager.runFunc(L, src, (Object[]) args);\n                //                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaAdapter.java",
    "content": "package androlua;\n\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\n\n/**\n * LuaAdapter\n * Created by hanks on 2017/5/13.\n */\n\npublic class LuaAdapter extends BaseAdapter {\n\n    AdapterCreator adapterCreator;\n\n    public LuaAdapter(AdapterCreator adapterCreator) {\n        this.adapterCreator = adapterCreator;\n    }\n\n    @Override\n    public int getCount() {\n        return (int) adapterCreator.getCount();\n    }\n\n    @Override\n    public Object getItem(int position) {\n        return adapterCreator.getItem(position);\n    }\n\n    @Override\n    public long getItemId(int position) {\n        return adapterCreator.getItemId(position);\n    }\n\n    @Override\n    public View getView(int position, View convertView, ViewGroup parent) {\n        return adapterCreator.getView(position, convertView, parent);\n    }\n\n    public interface AdapterCreator {\n        long getCount();\n\n        Object getItem(int position);\n\n        long getItemId(int position);\n\n        View getView(int position, View convertView, ViewGroup parent);\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaBitmap.java",
    "content": "package androlua;\n\n\nimport android.content.Context;\nimport android.content.res.AssetManager;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.ref.WeakReference;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.util.WeakHashMap;\n\npublic class LuaBitmap {\n    static WeakHashMap<String, WeakReference<Bitmap>> cache = new WeakHashMap<String, WeakReference<Bitmap>>();\n\n    private static int l;\n\n    public static boolean checkCache(LuaContext context, String url) {\n        // TODO: Implement this method\n        String path = LuaManager.getInstance().getLuaExtDir() + \"/\" + url.hashCode();\n        File f = new File(path);\n        return f.exists();\n    }\n\n    public static Bitmap getLoacalBitmap(String url) throws FileNotFoundException, IOException {\n\n        FileInputStream fis = new FileInputStream(url);\n        Bitmap bitmap = BitmapFactory.decodeStream(fis);\n        fis.close();\n        return bitmap;\n    }\n\n    public static Bitmap getLoacalBitmap(LuaContext context, String url) {\n        return decodeScale(1080, new File(url));\n    }\n\n    public static Bitmap getHttpBitmap(String url) throws IOException {\n        //Log.d(TAG, url);\n        URL myFileUrl = new URL(url);\n        HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();\n        //conn.setConnectTimeout(0);\n        conn.setDoInput(true);\n        conn.connect();\n        InputStream is = conn.getInputStream();\n        Bitmap bitmap = BitmapFactory.decodeStream(is);\n        is.close();\n        return bitmap;\n    }\n\n    public static Bitmap getHttpBitmap(LuaContext context, String url) throws IOException {\n        //Log.d(TAG, url);\n        String path = LuaManager.getInstance().getLuaExtDir() + \"/\" + url.hashCode();\n        File f = new File(path);\n        if (f.exists()) {\n            try {\n                /*HttpURLConnection con=(HttpURLConnection) new URL(url).openConnection();\n                con.setRequestMethod(\"HEAD\");\n\t\t\t\tcon.setConnectTimeout(1000);\n\t\t\t\tcon.connect();\n\t\t\t\tl = con.getContentLength();\n\t\t\t\tandroid.util.Log.d(\"lua\",l+\",\"+f.length());\n\t\t\t\tif(l==f.length())*/\n                return decodeScale(1080, new File(path));\n            } catch (Exception e) {\n                return decodeScale(1080, new File(path));\n            }\n        }\n        URL myFileUrl = new URL(url);\n        HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();\n        //conn.setConnectTimeout(0);\n        conn.setDoInput(true);\n        conn.connect();\n        InputStream is = conn.getInputStream();\n        FileOutputStream out = new FileOutputStream(path);\n        //LuaUtil.copyFile(is, out);\n        //Bitmap bitmap = BitmapFactory.decodeStream(is);\n        Bitmap bitmap = decodeScale(1080, new File(path));\n        is.close();\n        return bitmap;\n    }\n\n    public static Bitmap getAssetBitmap(Context context, String name) throws IOException {\n        AssetManager am = context.getAssets();\n        InputStream is = am.open(name);\n        Bitmap bitmap = BitmapFactory.decodeStream(is);\n        is.close();\n        return bitmap;\n    }\n\n    public static Bitmap getBitmap(LuaContext context, String path) throws IOException {\n\n        WeakReference<Bitmap> wRef = cache.get(path);\n        if (wRef != null) {\n            Bitmap bt = wRef.get();\n            if (bt != null)\n                return bt;\n        }\n\n        Bitmap bitmap;\n        if (path.indexOf(\"http://\") == 0) {\n            bitmap = getHttpBitmap(context, path);\n        } else if (path.charAt(0) != '/') {\n            bitmap = getLoacalBitmap(context, LuaManager.getInstance().getLuaDir() + \"/\" + path);\n        } else {\n            bitmap = getLoacalBitmap(context, path);\n        }\n\n        cache.put(path, new WeakReference<Bitmap>(bitmap));\n        return bitmap;\n    }\n\n    private static Bitmap decodeScale(int IMAGE_MAX_SIZE, File fis) {\n        Bitmap b = null;\n\n        BitmapFactory.Options o = new BitmapFactory.Options();\n        o.inJustDecodeBounds = true;\n        BitmapFactory.decodeFile(fis.getAbsolutePath(), o);\n        int scale = 1;\n        if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {\n            scale = (int) Math.pow(2, (int) Math.round(Math.log(IMAGE_MAX_SIZE / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));\n        }\n        BitmapFactory.Options o2 = new BitmapFactory.Options();\n        o2.inSampleSize = scale;\n\n        b = BitmapFactory.decodeFile(fis.getAbsolutePath(), o2);\n\n\n        return b;\n    }\n\n    public static Bitmap getImageFromPath(String filePath) {\n\n        Bitmap bitmap = null;\n        BitmapFactory.Options opts = new BitmapFactory.Options();\n        opts.inJustDecodeBounds = true;\n        BitmapFactory.decodeFile(filePath, opts);\n\n        //缩放图片，避免内存不足\n        opts.inSampleSize = computeSampleSize(opts, -1, 250 * 250);\n        opts.inJustDecodeBounds = false;\n\n        try {\n            bitmap = BitmapFactory.decodeFile(filePath, opts);\n        } catch (Exception e) {\n            // TODO: handle exception\n        }\n        return bitmap;\n    }\n\n    //缩放图片算法\n    private static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {\n        int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);\n        int roundedSize;\n        if (initialSize <= 8) {\n            roundedSize = 1;\n            while (roundedSize < initialSize) {\n                roundedSize <<= 1;\n            }\n        } else {\n            roundedSize = (initialSize + 7) / 8 * 8;\n        }\n        return roundedSize;\n    }\n\n    private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {\n        double w = options.outWidth;\n        double h = options.outHeight;\n        int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));\n        int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));\n        if (upperBound < lowerBound) {\n            // return the larger one when there is no overlapping zone.\n            return lowerBound;\n        }\n        if ((maxNumOfPixels == -1) && (minSideLength == -1)) {\n            return 1;\n        } else if (minSideLength == -1) {\n            return lowerBound;\n        } else {\n            return upperBound;\n        }\n    }\n\n    public static Bitmap getBitmapFromFile(File file, int width, int height) {\n\n        BitmapFactory.Options opts = null;\n        if (null != file && file.exists()) {\n\n            if (width > 0 && height > 0) {\n                opts = new BitmapFactory.Options();\n                // 只是返回的是图片的宽和高，并不是返回一个Bitmap对象\n                opts.inJustDecodeBounds = true;\n                // 信息没有保存在bitmap里面，而是保存在options里面\n                BitmapFactory.decodeFile(file.getPath(), opts);\n                // 计算图片缩放比例\n                final int minSideLength = Math.min(width, height);\n                // 缩略图大小为原始图片大小的几分之一。根据业务需求来做。\n                opts.inSampleSize = computeSampleSize(opts, minSideLength,\n                        width * height);\n                // 重新读入图片，注意此时已经把options.inJustDecodeBounds设回false\n                opts.inJustDecodeBounds = false;\n                // 设置是否深拷贝，与inPurgeable结合使用\n                opts.inInputShareable = true;\n                // 设置为True时，表示系统内存不足时可以被回 收，设置为False时，表示不能被回收。\n                opts.inPurgeable = true;\n            }\n            try {\n                return BitmapFactory.decodeFile(file.getPath(), opts);\n            } catch (OutOfMemoryError e) {\n                e.printStackTrace();\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaBroadcastReceiver.java",
    "content": "package androlua;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\npublic class LuaBroadcastReceiver extends BroadcastReceiver {\n\n    private OnReceiveListener mRlt;\n\n    public LuaBroadcastReceiver(OnReceiveListener rlt) {\n        mRlt = rlt;\n    }\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        if (mRlt == null) {\n            return;\n        }\n        mRlt.onReceive(context, intent);\n    }\n\n    public interface OnReceiveListener {\n        void onReceive(Context context, Intent intent);\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaContext.java",
    "content": "package androlua;\n\npublic interface LuaContext {\n\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaDexClassLoader.java",
    "content": "package androlua;\n\nimport java.util.HashMap;\n\nimport dalvik.system.DexClassLoader;\n\npublic class LuaDexClassLoader extends DexClassLoader {\n    private HashMap<String, Class<?>> classCache = new HashMap();\n    private String mDexPath;\n\n    public LuaDexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) {\n        super(dexPath, optimizedDirectory, libraryPath, parent);\n        this.mDexPath = dexPath;\n    }\n\n    public String getDexPath() {\n        return this.mDexPath;\n    }\n\n    protected Class<?> findClass(String name) throws ClassNotFoundException {\n        Class<?> cls = (Class) this.classCache.get(name);\n        if (cls != null) {\n            return cls;\n        }\n        cls = super.findClass(name);\n        this.classCache.put(name, cls);\n        return cls;\n    }\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaDexLoader.java",
    "content": "package androlua;\n\n\nimport android.content.res.AssetManager;\nimport android.content.res.Resources;\nimport android.content.res.Resources.Theme;\n\nimport com.luajava.LuaException;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.HashMap;\n\nimport dalvik.system.DexClassLoader;\n\npublic class LuaDexLoader {\n    private static HashMap<String, LuaDexClassLoader> dexCache = new HashMap();\n    private final LuaManager luaManager;\n    private ArrayList<ClassLoader> dexList = new ArrayList();\n    private HashMap<String, String> libCache = new HashMap();\n    private String luaDir;\n    private AssetManager mAssetManager;\n    private LuaContext mContext;\n    private Resources mResources;\n    private Theme mTheme;\n    private String odexDir;\n\n    public LuaDexLoader() {\n        luaManager = LuaManager.getInstance();\n        this.luaDir = luaManager.getLuaDir();\n        this.odexDir = luaManager.getOdexDir();\n    }\n\n    public Theme getTheme() {\n        return this.mTheme;\n    }\n\n    public ArrayList<ClassLoader> getClassLoaders() {\n        return this.dexList;\n    }\n\n    public void loadLibs() throws LuaException {\n        File[] libs = new File(LuaManager.getInstance().getLuaExtDir() + \"/libs\").listFiles();\n        if (libs != null) {\n            for (File f : libs) {\n                if (f.getAbsolutePath().endsWith(\".so\")) {\n                    loadLib(f.getName());\n                } else {\n                    loadDex(f.getAbsolutePath());\n                }\n            }\n        }\n    }\n\n    public void loadLib(String name) throws LuaException {\n//        String fn = name;\n//        int i = name.indexOf(\".\");\n//        if (i > 0) {\n//            fn = name.substring(0, i);\n//        }\n//        if (fn.startsWith(\"lib\")) {\n//            fn = fn.substring(3);\n//        }\n//        String libPath = this.mContext.getContext().getDir(fn, 0).getAbsolutePath() + \"/lib\" + fn + \".so\";\n//        if (!new File(libPath).exists()) {\n//            if (new File(this.luaDir + \"/libs/lib\" + fn + \".so\").exists()) {\n//                LuaUtil.copyFile(this.luaDir + \"/libs/lib\" + fn + \".so\", libPath);\n//            } else {\n//                throw new LuaException(\"can not find lib \" + name);\n//            }\n//        }\n//        this.libCache.put(fn, libPath);\n    }\n\n    public HashMap<String, String> getLibrarys() {\n        return this.libCache;\n    }\n\n    public DexClassLoader loadDex(String path) throws LuaException {\n        String name = path;\n        LuaDexClassLoader dex = (LuaDexClassLoader) dexCache.get(name);\n//        if (dex == null) {\n//            if (path.charAt(0) != '/') {\n//                path = this.luaDir + \"/\" + path;\n//            }\n//            if (!new File(path).exists()) {\n//                if (new File(path + \".dex\").exists()) {\n//                    path = path + \".dex\";\n//                } else if (new File(path + \".jar\").exists()) {\n//                    path = path + \".jar\";\n//                } else {\n//                    throw new LuaException(path + \" not found\");\n//                }\n//            }\n//            dex = new LuaDexClassLoader(path, this.odexDir,luaManager.getContext().getApplicationInfo().nativeLibraryDir, this.mContext.getContext().getClassLoader());\n//            dexCache.put(name, dex);\n//        }\n//        if (!this.dexList.contains(dex)) {\n//            this.dexList.add(dex);\n//            path = dex.getDexPath();\n//            if (path.endsWith(\".jar\")) {\n//                loadResources(path);\n//            }\n//        }\n        return dex;\n    }\n\n    public void loadResources(String path) {\n        try {\n//            AssetManager assetManager = (AssetManager) AssetManager.class.newInstance();\n//            if (((Integer) assetManager.getClass().getMethod(\"addAssetPath\", new Class[]{String.class}).invoke(assetManager, new Object[]{path})).intValue() != 0) {\n//                this.mAssetManager = assetManager;\n//                Resources superRes = this.mContext.getContext().getResources();\n//                this.mResources = new Resources(this.mAssetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());\n//                this.mTheme = this.mResources.newTheme();\n//                this.mTheme.setTo(this.mContext.getContext().getTheme());\n//            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public AssetManager getAssets() {\n        return this.mAssetManager;\n    }\n\n    public Resources getResources() {\n        return this.mResources;\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaDrawable.java",
    "content": "package androlua;\n\n\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.graphics.ColorFilter;\nimport android.graphics.Paint;\nimport android.graphics.PixelFormat;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\n\nimport com.luajava.LuaException;\nimport com.luajava.LuaFunction;\nimport com.luajava.LuaObject;\n\nimport androlua.common.LuaLog;\n\npublic class LuaDrawable extends Drawable {\n    private LuaObject mDraw;\n    private final LuaContext mContext = this.mDraw.getLuaState().getContext();\n    private LuaFunction mOnDraw;\n    private Paint mPaint = new Paint();\n\n    public LuaDrawable(LuaFunction func) {\n        this.mDraw = func;\n    }\n\n    public static Drawable create(String filePath) {\n        if (!filePath.startsWith(\"/\")) {\n            filePath = LuaManager.getInstance().getLuaExtDir() + \"/\" + filePath;\n        }\n        return new BitmapDrawable(LuaManager.getInstance().getContext().getResources(), BitmapFactory.decodeFile(filePath));\n    }\n\n    public void draw(Canvas p1) {\n        try {\n            if (this.mOnDraw == null) {\n                Object r = this.mDraw.call(p1, this.mPaint, this);\n                if (r != null && (r instanceof LuaFunction)) {\n                    this.mOnDraw = (LuaFunction) r;\n                }\n            }\n            if (this.mOnDraw != null) {\n                this.mOnDraw.call(p1);\n            }\n        } catch (LuaException e) {\n            LuaLog.e(e);\n        }\n    }\n\n    public void setAlpha(int p1) {\n        this.mPaint.setAlpha(p1);\n    }\n\n    public void setColorFilter(ColorFilter p1) {\n        this.mPaint.setColorFilter(p1);\n    }\n\n    public int getOpacity() {\n        return PixelFormat.UNKNOWN;\n    }\n\n    public Paint getPaint() {\n        return this.mPaint;\n    }\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaFragment.java",
    "content": "package androlua;\n\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.Fragment;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\n/**\n * Created by hanks on 2017/5/26. Copyright (C) 2017 Hanks\n */\n\npublic class LuaFragment extends Fragment {\n\n    private FragmentCreator creator;\n\n    public static LuaFragment newInstance() {\n        Bundle args = new Bundle();\n        LuaFragment fragment = new LuaFragment();\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    @Override\n    public void onPause() {\n        super.onPause();\n        if (creator != null) {\n            creator.onPause();\n        }\n    }\n\n    @Override\n    public void setUserVisibleHint(boolean isVisibleToUser) {\n        super.setUserVisibleHint(isVisibleToUser);\n        if (creator != null) creator.onUserVisible(isVisibleToUser);\n    }\n\n    public void setCreator(FragmentCreator creator) {\n        this.creator = creator;\n    }\n\n    @Override\n    public void onAttach(Context context) {\n        super.onAttach(context);\n        if (creator != null)creator.onAttach(context);\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        if (creator != null)creator.onCreate(savedInstanceState);\n        super.onCreate(savedInstanceState);\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        if (creator != null) {\n            return creator.onCreateView(inflater, container, savedInstanceState);\n        }\n        return super.onCreateView(inflater, container, savedInstanceState);\n    }\n\n    @Override\n    public void onActivityCreated(@Nullable Bundle savedInstanceState) {\n        super.onActivityCreated(savedInstanceState);\n        if (creator != null)creator.onActivityCreated(savedInstanceState);\n    }\n\n    @Override\n    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        if (creator != null)creator.onViewCreated(view, savedInstanceState);\n    }\n\n\n    @Override\n    public void onStart() {\n        if (creator != null) creator.onStart();\n        super.onStart();\n    }\n\n    @Override\n    public void onResume() {\n        if (creator != null)creator.onResume();\n        super.onResume();\n    }\n\n    @Override\n    public void onStop() {\n        if (creator != null)creator.onStop();\n        super.onStop();\n    }\n\n    @Override\n    public void onDestroyView() {\n        super.onDestroyView();\n        if (creator != null)creator.onDestroyView();\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (creator != null)creator.onDestroy();\n    }\n\n    @Override\n    public void onDetach() {\n        super.onDetach();\n        if (creator != null)creator.onDetach();\n    }\n\n    public interface FragmentCreator {\n        void onCreate(@Nullable Bundle savedInstanceState);\n\n        void onAttach(Context context);\n\n        View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState);\n\n        void onActivityCreated(Bundle savedInstanceState);\n\n        void onViewCreated(View view, @Nullable Bundle savedInstanceState);\n\n        void onStart();\n\n        void onResume();\n\n        void onStop();\n\n        void onPause();\n\n        void onDestroyView();\n\n        void onDestroy();\n\n        void onDetach();\n\n        void onUserVisible(boolean isVisibleToUser);\n\n    }\n\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaGcable.java",
    "content": "package androlua;\n\n\npublic interface LuaGcable {\n    void gc();\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaHttp.java",
    "content": "package androlua;\n\nimport android.support.annotation.NonNull;\n\nimport com.luajava.LuaException;\nimport com.luajava.LuaObject;\nimport com.luajava.LuaTable;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\nimport androlua.common.LuaFileUtils;\nimport androlua.common.LuaLog;\nimport okhttp3.Call;\nimport okhttp3.Callback;\nimport okhttp3.FormBody;\nimport okhttp3.MediaType;\nimport okhttp3.MultipartBody;\nimport okhttp3.OkHttpClient;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\nimport okhttp3.Response;\nimport okhttp3.logging.HttpLoggingInterceptor;\nimport pub.hanks.luajandroid.BuildConfig;\n\n/**\n * context client for lua\n * Created by hanks on 2017/5/15. Copyright (C) 2017 Hanks\n */\n\npublic class LuaHttp {\n\n    private static LuaHttp instance;\n    private final OkHttpClient httpClient;\n\n    private LuaHttp() {\n\n        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();\n        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);\n        OkHttpClient.Builder builder = new OkHttpClient.Builder();\n        if (!\"release\".equals(BuildConfig.BUILD_TYPE)) {\n            builder.addInterceptor(interceptor);\n        }\n        httpClient = builder.build();\n\n    }\n\n    public static LuaHttp getInstance() {\n        if (instance == null) {\n            synchronized (LuaHttp.class) {\n                if (instance == null) {\n                    instance = new LuaHttp();\n                }\n            }\n        }\n        return instance;\n    }\n\n    public static void cancelAll() {\n        getInstance().httpClient.dispatcher().cancelAll();\n    }\n\n    public static void request(final LuaTable options, final LuaObject callback) {\n        getInstance().httpClient.newCall(buildRequest(options))\n                .enqueue(new Callback() {\n                    @Override\n                    public void onFailure(Call call, IOException e) {\n                        try {\n                            callback.call(e);\n                        } catch (LuaException e1) {\n                            LuaLog.e(e1);\n                        }\n                    }\n\n                    @Override\n                    public void onResponse(Call call, Response response) throws IOException {\n                        try {\n                            Object o = options.get(\"outputFile\");\n                            if (o != null) {\n                                InputStream inputStream = response.body().byteStream();\n                                String filePath;\n                                if (o instanceof String) {\n                                    filePath = (String) o;\n                                } else {\n                                    filePath = o.toString();\n                                }\n                                String outputFile = LuaFileUtils.saveToFile(inputStream, filePath);\n                                callback.call(null, response.code(), outputFile);\n                                return;\n                            }\n                            callback.call(null, response.code(), response.body().string());\n                        } catch (LuaException e) {\n                            LuaLog.e(e);\n                        }\n                    }\n                });\n    }\n\n    public static void requestSync(final LuaTable options, final LuaObject callback) {\n        try {\n            Response response = getInstance().httpClient.newCall(buildRequest(options)).execute();\n            Object o = options.get(\"outputFile\");\n            if (o != null) {\n                InputStream inputStream = response.body().byteStream();\n                String filePath;\n                if (o instanceof String) {\n                    filePath = (String) o;\n                } else {\n                    filePath = o.toString();\n                }\n                String outputFile = LuaFileUtils.saveToFile(inputStream, filePath);\n                callback.call(null, response.code(), outputFile);\n                return;\n            }\n            callback.call(null, response.code(), response.body().string());\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    @NonNull\n    private static Request buildRequest(LuaTable options) {\n        Request.Builder builder = new Request.Builder();\n        String url = (String) options.get(\"url\");\n        builder.url(url);\n\n        String method = (String) options.get(\"method\");\n        if (\"GET\".equals(method)) {\n            builder.get();\n        } else if (\"POST\".equals(method)) {\n            RequestBody requestBody = getRequestBody(options);\n            if (requestBody != null) {\n                builder.post(requestBody);\n            }\n        } else if (\"PUT\".equals(method)) {\n            RequestBody requestBody = getRequestBody(options);\n            if (requestBody != null) {\n                builder.put(requestBody);\n            }\n        } else if (\"DELETE\".equals(method)) {\n            RequestBody requestBody = getRequestBody(options);\n            if (requestBody != null) {\n                builder.delete(requestBody);\n            } else {\n                builder.delete();\n            }\n        } else {\n            builder.get();\n        }\n\n        LuaTable headers = (LuaTable) options.get(\"headers\");\n        if (headers != null) {\n            for (Object key : headers.keySet()) {\n                String value = (String) headers.get(key);\n                int i = value.indexOf(\":\");\n                if (i == -1) {\n                    continue;\n                }\n                String[] header = new String[]{\n                        value.substring(0, i),\n                        value.substring(i + 1)\n                };\n                builder.header(header[0].trim(), header[1].trim());\n            }\n        }\n        return builder.build();\n    }\n\n    private static RequestBody getRequestBody(LuaTable options) {\n\n        String body = (String) options.get(\"body\");\n        if (body != null) {\n            return RequestBody.create(MediaType.parse(\"application/json; charset=utf-8\"), body);\n        }\n\n\n        Map formData = (Map) options.get(\"formData\");\n        if (formData != null) {\n            FormBody.Builder bodyBuilder = new FormBody.Builder();\n            for (Object key : formData.keySet()) {\n                String value = (String) formData.get(key);\n                int i = value.indexOf(\":\");\n                if (i == -1) {\n                    continue;\n                }\n                String[] params = new String[]{\n                        value.substring(0, i),\n                        value.substring(i + 1)\n                };\n                bodyBuilder.add(params[0].trim(), params[1].trim());\n            }\n            return bodyBuilder.build();\n        }\n\n        Map multipart = (Map) options.get(\"multipart\");\n        if (multipart != null) {\n            MultipartBody.Builder bodyBuilder = new MultipartBody.Builder()\n                    .setType(MultipartBody.FORM);\n            for (Object key : multipart.keySet()) {\n                String value = (String) multipart.get(key);\n                int i = value.indexOf(\":\");\n                if (i == -1) {\n                    continue;\n                }\n                String[] params = new String[]{\n                        value.substring(0, i),\n                        value.substring(i + 1)\n                };\n                String itemKey = params[0].trim();\n                String itemValue = params[1].trim();\n                if (itemValue.startsWith(\"/\")) {\n                    File file = new File(itemValue);\n                    if (file.exists()) {\n                        bodyBuilder.addFormDataPart(itemKey, file.getName(),\n                                RequestBody.create(MediaType.parse(\"image/png\"), file));\n                    }\n                } else {\n                    bodyBuilder.addFormDataPart(itemKey, itemValue);\n                }\n            }\n            return bodyBuilder.build();\n        }\n        return new FormBody.Builder().build();\n    }\n\n    public static boolean downloadFile(String url, String savePath) {\n        return downloadFile(url, savePath, null);\n    }\n\n    public static boolean downloadFile(String url, String savePath, ArrayList<String> headers) {\n        try {\n            final File file = new File(savePath);\n            if (file.exists()) {\n                return true;\n            }\n            OkHttpClient client = new OkHttpClient.Builder()\n                    .connectTimeout(10, TimeUnit.SECONDS)\n                    .writeTimeout(10, TimeUnit.SECONDS)\n                    .readTimeout(30, TimeUnit.SECONDS)\n                    .build();\n            Request.Builder builder = new Request.Builder().url(url);\n            if (headers != null) {\n                for (String header : headers) {\n                    int i = header.indexOf(\":\");\n                    if (i <= 0) {\n                        continue;\n                    }\n                    String key = header.substring(0, i);\n                    String v = header.substring(i + 1);\n                    builder.addHeader(key, v);\n                }\n            }\n            final Request request = builder.build();\n            Response response = client.newCall(request).execute();\n\n            InputStream is = null;\n            byte[] buf = new byte[2048];\n            FileOutputStream fos = null;\n            try {\n                is = response.body().byteStream();\n                fos = new FileOutputStream(file);\n                int len = 0;\n                while ((len = is.read(buf)) != -1) {\n                    fos.write(buf, 0, len);\n                }\n                fos.flush();\n            } catch (IOException e) {\n                LuaLog.e(e);\n            } finally {\n                try {\n                    if (is != null) {\n                        is.close();\n                    }\n                    if (fos != null) {\n                        fos.close();\n                    }\n                } catch (IOException e) {\n                    LuaLog.e(e);\n                }\n            }\n            return true;\n        } catch (IOException e) {\n            LuaLog.e(e);\n            return false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaImageLoader.java",
    "content": "package androlua;\n\nimport android.content.Context;\nimport android.graphics.BitmapFactory;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.GradientDrawable;\nimport android.support.v4.content.ContextCompat;\nimport android.util.Log;\nimport android.widget.ImageView;\n\nimport com.bumptech.glide.DrawableTypeRequest;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.model.GlideUrl;\nimport com.bumptech.glide.load.model.LazyHeaders;\nimport com.bumptech.glide.load.resource.bitmap.CenterCrop;\n\nimport jp.wasabeef.glide.transformations.BlurTransformation;\nimport jp.wasabeef.glide.transformations.RoundedCornersTransformation;\nimport pub.hanks.luajandroid.R;\n\n/**\n * user image loader\n * Created by hanks on 2017/5/12. Copyright (C) 2017 Hanks\n */\n\npublic class LuaImageLoader {\n\n    public static void load(ImageView imageView, String uri) {\n        load(imageView.getContext(), imageView, uri);\n    }\n    public static void loadWithRadius(ImageView imageView, float radius, String uri) {\n        Context context = imageView.getContext();\n        GradientDrawable gd = new GradientDrawable();\n        gd.setCornerRadius(LuaUtil.dp2px(radius));\n        gd.setColor(0xffebf0f2);\n        load(context, imageView, uri, radius, 0, gd, gd);\n\n    }\n\n    public static void load(Context context, ImageView imageView, String uri) {\n\n        load(context, imageView, uri, 0, 0,\n                ContextCompat.getDrawable(context, R.drawable.ic_loading),\n                ContextCompat.getDrawable(context, R.drawable.ic_loading));\n    }\n\n    public static void load(Context context, ImageView imageView, String uri, float radius, float blueRadius,\n                            Drawable placeholderDrawable, Drawable errorDrawable) {\n        if (imageView == null || uri == null) {\n            return;\n        }\n        boolean loadLocal = false;\n        if (uri.startsWith(\"#\")) { // load local file\n            uri = uri.substring(1);\n            loadLocal = true;\n        }\n\n        if (!uri.startsWith(\"http://\") && !uri.startsWith(\"https://\")\n                && !uri.startsWith(\"content://\") && !uri.startsWith(\"file://\")) {\n            String path = uri;\n            if (!uri.startsWith(\"/\")) {\n                path = LuaManager.getInstance().getLuaExtDir() + \"/\" + uri;\n            }\n            if (loadLocal) {\n                imageView.setImageBitmap(BitmapFactory.decodeFile(path));\n                return;\n            }\n            uri = \"file://\" + path;\n        }\n        DrawableTypeRequest manager = Glide.with(context).load(uri);\n        BlurTransformation blurTransformation = null;\n        RoundedCornersTransformation roundedCornersTransformation = null;\n\n        if (radius > 0){\n            roundedCornersTransformation = new RoundedCornersTransformation(context, LuaUtil.dp2px(radius), 0);\n        }\n        if (blueRadius > 0) {\n            blurTransformation = new BlurTransformation(context, (int) blueRadius);\n        }\n        if (radius > 0 && blueRadius > 0) {\n            manager.bitmapTransform(new CenterCrop(context),roundedCornersTransformation, blurTransformation);\n        } else if (radius > 0) {\n            manager.bitmapTransform(new CenterCrop(context),roundedCornersTransformation);\n        } else if (blueRadius > 0) {\n            manager.bitmapTransform(new CenterCrop(context),blurTransformation);\n        }\n        manager\n                .placeholder(placeholderDrawable)\n                .error(errorDrawable)\n                .crossFade()\n                .into(imageView);\n    }\n\n    public static void load(ImageView imageView, String uri, String referer) {\n        if (imageView == null || uri == null) {\n            return;\n        }\n        LazyHeaders headers = new LazyHeaders.Builder()\n                .addHeader(\"Referer\", referer)\n                .build();\n        GlideUrl glideUrl = new GlideUrl(uri, headers);\n        Glide.with(imageView.getContext())\n                .load(glideUrl)\n                .placeholder(R.drawable.ic_loading)\n                .error(R.drawable.ic_loading)\n                .crossFade()\n                .into(imageView);\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaManager.java",
    "content": "package androlua;\n\nimport android.content.Context;\n\nimport com.luajava.JavaFunction;\nimport com.luajava.LuaException;\nimport com.luajava.LuaObject;\nimport com.luajava.LuaState;\nimport com.luajava.LuaStateFactory;\n\nimport java.io.File;\n\nimport androlua.common.LuaFileUtils;\nimport androlua.common.LuaLog;\nimport dalvik.system.DexClassLoader;\n\npublic class LuaManager {\n\n    private static LuaManager instance;\n    private Context context;\n    private String odexDir;\n    private String libDir; // 外部 so 文件路径\n    private String luaDir; // 内部 lua 文件路径\n    private String luaExtDir; // 外部 lua 文件路径\n    private String luaCpath; // 相当于 LUA_CPATH\n    private String luaLpath; // 相当于 LUA_PATH\n    private boolean debugable = true;\n\n    private LuaManager() {\n\n    }\n\n    public static LuaManager getInstance() {\n        if (instance == null) {\n            synchronized (LuaManager.class) {\n                if (instance == null) {\n                    instance = new LuaManager();\n                }\n            }\n        }\n        return instance;\n    }\n\n    public void init(Context context) {\n        this.context = context;\n        // 注册crashHandler\n        // CrashHandler crashHandler = CrashHandler.getInstance();\n        // crashHandler.init(context.getApplicationContext());\n\n        //初始化AndroLua工作目录\n        luaExtDir = LuaFileUtils.getAndroLuaDir();\n        //定义文件夹\n        odexDir = context.getDir(\"odex\", Context.MODE_PRIVATE).getAbsolutePath();\n        libDir = context.getDir(\"lib\", Context.MODE_PRIVATE).getAbsolutePath();\n        luaDir = context.getDir(\"lua\", Context.MODE_PRIVATE).getAbsolutePath();\n        luaCpath = context.getApplicationInfo().nativeLibraryDir + \"/lib?.so\" + \";\" + libDir + \"/lib?.so\";\n        luaLpath = luaDir + \"/?.lua;\" + luaDir + \"/lua/?.lua;\" + luaDir + \"/?/initEnv.lua;\" + luaExtDir + \"/?.lua;\";\n    }\n\n    public boolean isDebugable() {\n        return debugable;\n    }\n\n    public LuaManager setDebugable(boolean debugable) {\n        this.debugable = debugable;\n        return this;\n    }\n\n    //运行lua脚本\n    public Object doFile(LuaState L, String filePath) throws LuaException {\n        return doFile(L, filePath, new Object[0]);\n    }\n\n    public Object doFile(LuaState L, String filePath, Object[] args) throws LuaException {\n        appendLuaDir(L, filePath);\n        int ok = 0;\n        L.setTop(0);\n        ok = L.LloadFile(filePath);\n        if (ok == 0) {\n            L.getGlobal(\"debug\");\n            L.getField(-1, \"traceback\");\n            L.remove(-2);\n            L.insert(-2);\n            int l = args.length;\n            for (Object arg : args) {\n                L.pushObjectValue(arg);\n            }\n            ok = L.pcall(l, 1, -2 - l);\n            if (ok == 0) {\n                return L.toJavaObject(-1);\n            }\n        }\n        throw new LuaException(errorReason(ok) + \": \" + L.toString(-1));\n    }\n\n\n    //运行lua函数\n    public Object runFunc(LuaState L, String funcName, Object... args) {\n        try {\n            L.setTop(0);\n            L.getGlobal(funcName);\n            if (L.isFunction(-1)) {\n                L.getGlobal(\"debug\");\n                L.getField(-1, \"traceback\");\n                L.remove(-2);\n                L.insert(-2);\n                int argsLength = args.length;\n                for (Object arg : args) {\n                    L.pushObjectValue(arg);\n                }\n                int ok = L.pcall(argsLength, 1, -2 - argsLength);\n                if (ok == 0) {\n                    return L.toJavaObject(-1);\n                }\n                throw new LuaException(errorReason(ok) + \": \" + L.toString(-1));\n            }\n        } catch (LuaException e) {\n            LuaLog.e(e);\n        }\n        return null;\n    }\n\n    //运行lua代码\n    public Object doString(LuaState L, String funcSrc, Object... args) throws LuaException {\n        L.setTop(0);\n        int ok = L.LloadString(funcSrc);\n        if (ok == 0) {\n            L.getGlobal(\"debug\");\n            L.getField(-1, \"traceback\");\n            L.remove(-2);\n            L.insert(-2);\n            int l = args.length;\n            for (Object arg : args) {\n                L.pushObjectValue(arg);\n            }\n            ok = L.pcall(l, 1, -2 - l);\n            if (ok == 0) {\n                return L.toJavaObject(-1);\n            }\n        }\n        throw new LuaException(errorReason(ok) + \": \" + L.toString(-1));\n    }\n\n\n    public DexClassLoader loadDex(ClassLoader parent, String path) throws LuaException {\n        if (path.charAt(0) != '/')\n            path = getLuaDir() + \"/\" + path;\n        if (!new File(path).exists())\n            if (new File(path + \".dex\").exists())\n                path += \".dex\";\n            else if (new File(path + \".jar\").exists())\n                path += \".jar\";\n            else\n                throw new LuaException(path + \" not found\");\n        return new DexClassLoader(path, odexDir, getContext().getApplicationInfo().nativeLibraryDir, parent);\n    }\n\n    public Object loadLib(LuaState L, String soPath) throws LuaException {\n        if (!soPath.startsWith(\"/\")) {\n            soPath = libDir + \"/\" + soPath;\n        }\n        File soFile = new File(soPath);\n        if (!soFile.exists()) {\n            throw new LuaException(\"can not find lib \" + soFile.getAbsolutePath());\n        }\n        if (!libDir.equals(soFile.getParent())) {\n            LuaUtil.copyFile(soFile.getAbsolutePath(), libDir + \"/lib\" + soFile.getName() + \".so\");\n        }\n        LuaObject require = L.getLuaObject(\"require\");\n        return require.call(soFile.getName());\n    }\n\n    //生成错误信息\n    private String errorReason(int error) {\n        switch (error) {\n            case 6:\n                return \"error error\";\n            case 5:\n                return \"GC error\";\n            case 4:\n                return \"Out of memory\";\n            case 3:\n                return \"Syntax error\";\n            case 2:\n                return \"Runtime error\";\n            case 1:\n                return \"Yield error\";\n        }\n        return \"Unknown error \" + error;\n    }\n\n    public void appendSoDir(String dir) {\n        if (!dir.startsWith(\"/\")) {\n            dir = getLibDir() + \"/\" + dir;\n        }\n        if (dir.endsWith(\".so\")) {\n            dir = dir.substring(0, dir.lastIndexOf('/'));\n        }\n        String newPath = String.format(\";%s/?.so\", dir);\n        if (luaCpath.contains(newPath)) {\n            return;\n        }\n        luaCpath += newPath;\n    }\n\n    public void appendLuaDir(LuaState L, String dir) {\n        if (!dir.startsWith(\"/\")) {\n            dir = getLuaExtDir() + \"/\" + dir;\n        }\n        if (dir.endsWith(\".lua\")) {\n            dir = dir.substring(0, dir.lastIndexOf('/'));\n        }\n        String newPath = String.format(\";%s/?.lua\", dir);\n        if (luaLpath.contains(newPath)) {\n            return;\n        }\n        luaLpath += newPath;\n        initLuaPath(L);\n    }\n\n    public Context getContext() {\n        return context;\n    }\n\n    public String getOdexDir() {\n        return odexDir;\n    }\n\n    public String getLibDir() {\n        return libDir;\n    }\n\n    public String getLuaDir() {\n        return luaDir;\n    }\n\n    public String getLuaExtDir() {\n        return luaExtDir;\n    }\n\n    public String getLuaCpath() {\n        return luaCpath;\n    }\n\n    public String getLuaLpath() {\n        return luaLpath;\n    }\n\n\n    public LuaState initLua() {\n        try {\n            LuaState L = LuaStateFactory.newLuaState();\n            L.openLibs();\n\n//            // push 一个 context\n//            L.pushJavaObject(getContext());\n//            // pop 并赋值给 activity\n//            L.setGlobal(\"activity\");\n//\n//            // 把全局变量 activity 的值 push 进栈\n//            L.getGlobal(\"activity\");\n//            // pop 并赋值给 this\n//            L.setGlobal(\"this\");\n//\n////            L.pushJavaObject(this);\n////            L.getGlobal(\"luajava\");\n//\n//            L.pushString(getLuaExtDir());\n//            L.setField(-2, \"luaextdir\");\n//\n//            L.pushString(getLuaDir());\n//            L.setField(-2, \"luadir\");\n//\n//\n//            L.pushString(getLuaLpath());\n//            L.setField(-2, \"luapath\");\n//\n//            // 彈出一个元素\n//            L.pop(1);\n\n            // 注册全局函数 print\n            JavaFunction print = new LuaPrint(L);\n            print.register(\"print\");\n\n            initLuaPath(L);\n            L.pop(1);\n            return L;\n        } catch (LuaException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    private void initLuaPath(LuaState L) {\n        L.getGlobal(\"package\");\n        L.pushString(getLuaLpath());\n        L.setField(-2, \"path\");\n        L.pushString(getLuaCpath());\n        L.setField(-2, \"cpath\");\n    }\n}\n\n\n\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaPrint.java",
    "content": "package androlua;\n\n\nimport android.util.Log;\n\nimport com.luajava.JavaFunction;\nimport com.luajava.LuaException;\nimport com.luajava.LuaState;\n\nimport androlua.common.LuaLog;\n\npublic class LuaPrint extends JavaFunction {\n\n    private LuaState L;\n    private StringBuilder output = new StringBuilder();\n\n    public LuaPrint(LuaState L) {\n        super(L);\n        this.L = L;\n    }\n\n    @Override\n    public int execute() throws LuaException {\n        if (L.getTop() < 2) {\n            LuaLog.e(\"error print\");\n            return 0;\n        }\n        for (int i = 2; i <= L.getTop(); i++) {\n            int type = L.type(i);\n            String val = null;\n            String stype = L.typeName(type);\n            if (stype.equals(\"userdata\")) {\n                Object obj = L.toJavaObject(i);\n                if (obj != null)\n                    val = obj.toString();\n            } else if (stype.equals(\"boolean\")) {\n                val = L.toBoolean(i) ? \"true\" : \"false\";\n            } else {\n                val = L.toString(i);\n            }\n            if (val == null)\n                val = stype;\n            output.append(\"\\t\");\n            output.append(val);\n            output.append(\"\\t\");\n        }\n        Log.e(\"Luandroid\", output.toString().substring(1, output.length() - 1));\n        output.setLength(0);\n        return 0;\n    }\n\n\n}\n\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaTimer.java",
    "content": "package androlua;\n\n\npublic class LuaTimer {\n//    private LuaTimerTask task;\n//\n//    public LuaTimer(LuaContext main, String src) throws LuaException {\n//        this(main, src, null);\n//    }\n//\n//    public LuaTimer(LuaContext main, String src, Object[] arg) throws LuaException {\n//        super(\"LuaTimer\");\n//        this.task = new LuaTimerTask(main, src, arg);\n//    }\n//\n//    public LuaTimer(LuaContext main, LuaObject func) throws LuaException {\n//        this(main, func, null);\n//    }\n//\n//    public LuaTimer(LuaContext main, LuaObject func, Object[] arg) throws LuaException {\n//        super(\"LuaTimer\");\n//        this.task = new LuaTimerTask(main, func, arg);\n//    }\n//\n//    public void gc() {\n//        stop();\n//    }\n//\n//    public void start(long delay, long period) {\n//        schedule(this.task, delay, period);\n//    }\n//\n//    public void start(long delay) {\n//        schedule(this.task, delay);\n//    }\n//\n//    public void stop() {\n//        this.task.cancel();\n//    }\n//\n//    public boolean isEnabled() {\n//        return this.task.isEnabled();\n//    }\n//\n//    public boolean getEnabled() {\n//        return this.task.isEnabled();\n//    }\n//\n//    public void setEnabled(boolean enabled) {\n//        this.task.setEnabled(enabled);\n//    }\n//\n//    public long getPeriod() {\n//        return this.task.getPeriod();\n//    }\n//\n//    public void setPeriod(long period) {\n//        this.task.setPeriod(period);\n//    }\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaUtil.java",
    "content": "package androlua;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.res.AssetManager;\nimport android.graphics.Bitmap;\nimport android.graphics.PixelFormat;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.util.DisplayMetrics;\nimport android.view.Display;\nimport android.view.WindowManager;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport androlua.common.LuaStringUtils;\n\npublic class LuaUtil {\n\n\n    /**\n     * 截屏\n     *\n     * @param activity\n     * @return\n     */\n    public static Bitmap captureScreen(Activity activity) {\n        // 获取屏幕大小：\n        DisplayMetrics metrics = new DisplayMetrics();\n        WindowManager WM = (WindowManager) activity\n                .getSystemService(Context.WINDOW_SERVICE);\n        Display display = WM.getDefaultDisplay();\n        display.getMetrics(metrics);\n        int height = metrics.heightPixels; // 屏幕高\n        int width = metrics.widthPixels; // 屏幕的宽\n        // 获取显示方式\n        int pixelformat = display.getPixelFormat();\n        PixelFormat localPixelFormat1 = new PixelFormat();\n        PixelFormat.getPixelFormatInfo(pixelformat, localPixelFormat1);\n        int deepth = localPixelFormat1.bytesPerPixel;// 位深\n        byte[] piex = new byte[height * width * deepth];\n        try {\n            Runtime.getRuntime().exec(\n                    new String[]{\"/system/bin/su\", \"-c\",\n                            \"chmod 777 /dev/graphics/fb0\"});\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        try {\n            // 获取fb0数据输入流\n            InputStream stream = new FileInputStream(new File(\n                    \"/dev/graphics/fb0\"));\n            DataInputStream dStream = new DataInputStream(stream);\n            dStream.readFully(piex);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        // 保存图片\n        int[] colors = new int[height * width];\n        for (int m = 0; m < colors.length; m++) {\n            int r = (piex[m * 4] & 0xFF);\n            int g = (piex[m * 4 + 1] & 0xFF);\n            int b = (piex[m * 4 + 2] & 0xFF);\n            int a = (piex[m * 4 + 3] & 0xFF);\n            colors[m] = (a << 24) + (r << 16) + (g << 8) + b;\n        }\n        // piex生成Bitmap\n        Bitmap bitmap = Bitmap.createBitmap(colors, width, height,\n                Bitmap.Config.ARGB_8888);\n        return bitmap;\n    }\n\n    public static byte[] readAsset(Context context, String name) throws IOException {\n        AssetManager am = context.getAssets();\n        InputStream is = am.open(name);\n        byte[] ret = readAll(is);\n        is.close();\n        //am.close();\n        return ret;\n    }\n\n    //读取asset文件\n\n    private static byte[] readAll(InputStream input) throws IOException {\n        ByteArrayOutputStream output = new ByteArrayOutputStream(4096);\n        byte[] buffer = new byte[4096];\n        int n = 0;\n        while (-1 != (n = input.read(buffer))) {\n            output.write(buffer, 0, n);\n        }\n        byte[] ret = output.toByteArray();\n        output.close();\n        return ret;\n    }\n\n    //复制asset文件到sd卡\n    public static void assetsToSD(Context context, String InFileName, String OutFileName) throws IOException {\n        InputStream myInput;\n        OutputStream myOutput = new FileOutputStream(OutFileName);\n        myInput = context.getAssets().open(InFileName);\n        byte[] buffer = new byte[8192];\n        int length = myInput.read(buffer);\n        while (length > 0) {\n            myOutput.write(buffer, 0, length);\n            length = myInput.read(buffer);\n        }\n\n        myOutput.flush();\n        myInput.close();\n        myOutput.close();\n    }\n\n    public static void copyFile(String oldPath, String newPath) {\n        try {\n            int bytesum = 0;\n            int byteread = 0;\n            File oldfile = new File(oldPath);\n            if (oldfile.exists()) { //文件存在时\n                InputStream inStream = new FileInputStream(oldPath); //读入原文件\n                FileOutputStream fs = new FileOutputStream(newPath);\n                byte[] buffer = new byte[4096];\n                int length;\n                while ((byteread = inStream.read(buffer)) != -1) {\n                    bytesum += byteread; //字节数 文件大小\n                    System.out.println(bytesum);\n                    fs.write(buffer, 0, byteread);\n                }\n                inStream.close();\n            }\n        } catch (Exception e) {\n            System.out.println(\"复制文件操作出错\");\n            e.printStackTrace();\n\n        }\n\n    }\n\n    public static void rmDir(File dir) {\n        File[] fs = dir.listFiles();\n        for (File f : fs) {\n            if (f.isDirectory())\n                rmDir(f);\n            else\n                f.delete();\n        }\n        dir.delete();\n    }\n\n    public static void rmDir(File dir, String ext) {\n        File[] fs = dir.listFiles();\n        for (File f : fs) {\n            if (f.isDirectory())\n                rmDir(f);\n            else if (f.getName().endsWith(ext))\n                f.delete();\n        }\n        //dir.delete();\n    }\n\n    public static Context getContext() {\n        return LuaManager.getInstance().getContext();\n    }\n\n    public static float getDensity() {\n        return getContext().getResources().getDisplayMetrics().density;\n    }\n\n    public static int dp2px(float dp) {\n        float density = getContext().getResources().getDisplayMetrics().density;\n        return (int) (0.5F + dp * density);\n    }\n\n    public static int getScreenWidth() {\n        return getContext().getResources().getDisplayMetrics().widthPixels;\n    }\n\n    protected int getStatusBarHeight() {\n        int identifier = getContext().getResources().getIdentifier(\"status_bar_height\", \"dimen\", \"android\");\n        if (identifier > 0) {\n            return getContext().getResources().getDimensionPixelSize(identifier);\n        }\n        return 0;\n    }\n\n    public static class IntentHelper {\n        public static String getLuaPath(Intent intent) {\n            String luaPath = intent.getStringExtra(\"luaPath\");\n            return LuaStringUtils.isEmpty(luaPath) ? \"main.lua\" : luaPath;\n\n        }\n\n        public static Object[] getArgs(Intent intent) {\n            Object[] arg = (Object[]) intent.getSerializableExtra(\"arg\");\n            if (arg == null)\n                arg = new Object[0];\n            return arg;\n        }\n    }\n\n    public static boolean isWifi(){\n        ConnectivityManager cm =\n                (ConnectivityManager)getContext().getSystemService(Context.CONNECTIVITY_SERVICE);\n        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();\n        return activeNetwork != null &&\n                activeNetwork.isConnectedOrConnecting() && activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;\n    }\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaView.java",
    "content": "package androlua;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.support.annotation.Nullable;\nimport android.util.AttributeSet;\nimport android.view.View;\n\n/**\n * custom view\n * Created by hanks on 2017/6/6.\n */\n\npublic class LuaView extends View {\n\n    private Creator creator;\n\n    public LuaView(Context context) {\n        this(context, null);\n    }\n\n    public LuaView(Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public LuaView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        if (creator != null) {\n            creator.init(context, attrs, defStyleAttr);\n        }\n    }\n\n    public void setCreator(Creator creator) {\n        this.creator = creator;\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n        if (creator != null) {\n            creator.onMeasure(widthMeasureSpec, heightMeasureSpec);\n        }\n    }\n\n    @Override\n    protected void onFinishInflate() {\n        super.onFinishInflate();\n        if (creator != null) {\n            creator.onFinishInflate();\n        }\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        if (creator != null) {\n            creator.onDraw(canvas);\n        }\n    }\n\n    public interface Creator {\n        void init(Context context, @Nullable AttributeSet attrs, int defStyleAttr);\n\n        void onDraw(Canvas canvas);\n\n        void onFinishInflate();\n\n        void onMeasure(int widthMeasureSpec, int heightMeasureSpec);\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/LuaWebView.java",
    "content": "package androlua;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.net.http.SslError;\nimport android.os.Build;\nimport android.support.v7.app.AlertDialog;\nimport android.util.AttributeSet;\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.webkit.HttpAuthHandler;\nimport android.webkit.SslErrorHandler;\nimport android.webkit.WebChromeClient;\nimport android.webkit.WebResourceError;\nimport android.webkit.WebResourceRequest;\nimport android.webkit.WebResourceResponse;\nimport android.webkit.WebSettings;\nimport android.webkit.WebView;\nimport android.webkit.WebViewClient;\n\nimport com.luajava.LuaException;\nimport com.luajava.LuaObject;\n\n/**\n * LuaWebView\n * Created by hanks on 2017/5/27.\n */\npublic class LuaWebView extends WebView {\n    private WebChromeClientListener webChromeClientListener;\n    private WebViewClientListener webViewClientListener;\n\n    public LuaWebView(Context context) {\n        this(context, null);\n    }\n\n    public LuaWebView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public LuaWebView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        if (Build.VERSION.SDK_INT >= 19) {\n            setLayerType(View.LAYER_TYPE_HARDWARE, null);\n        } else {\n            setLayerType(View.LAYER_TYPE_SOFTWARE, null);\n        }\n        WebSettings setting = getSettings();\n        setting.setSupportZoom(false);\n        setting.setBuiltInZoomControls(false);\n        setting.setDefaultFontSize(14);\n        setting.setDefaultFixedFontSize(14);\n        setting.setUseWideViewPort(true);\n        setting.setLoadWithOverviewMode(true);\n        setting.setDomStorageEnabled(true);\n        setting.setAllowContentAccess(true);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n            setting.setAllowFileAccessFromFileURLs(true);\n        }\n        setting.setAppCacheEnabled(true);\n        setting.setDatabaseEnabled(true);\n        setting.setSaveFormData(true);\n        setting.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);\n        setting.setAllowFileAccess(true);\n        setting.setJavaScriptEnabled(true);\n        setWebChromeClient(new LuaWebChromeClient());\n        setWebViewClient(new LuaWebViewClient());\n        if (Build.VERSION.SDK_INT >= 19) {\n            setWebContentsDebuggingEnabled(true);\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            setting.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);\n        }\n\n        setFocusable(true);\n        setFocusableInTouchMode(true);\n    }\n\n    public void release() {\n        if (getParent() == null || !(getParent() instanceof ViewGroup)) {\n            return;\n        }\n        ((ViewGroup) getParent()).removeView(this);\n        destroy();\n    }\n\n\n    public void injectObjectToJavascript(LuaObject luaObject, String objectName) {\n        addJavascriptInterface(new JavascriptInterface(luaObject), objectName);\n    }\n\n    public void setWebChromeClientListener(WebChromeClientListener webChromeClientListener) {\n        this.webChromeClientListener = webChromeClientListener;\n    }\n\n    public void setWebViewClientListener(WebViewClientListener webViewClientListener) {\n        this.webViewClientListener = webViewClientListener;\n    }\n\n    public interface WebViewClientListener {\n        boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request);\n\n        boolean shouldOverrideKeyEvent(WebView view, KeyEvent event);\n\n        WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request);\n\n        void onPageFinished(WebView view, String url);\n\n        void onPageStarted(WebView view, String url, Bitmap favicon);\n\n        void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error);\n\n    }\n\n    public interface WebChromeClientListener {\n\n        void onProgressChanged(WebView view, int newProgress);\n\n        void onReceivedTitle(WebView view, String title);\n\n        void onReceivedIcon(WebView view, Bitmap icon);\n\n        void onReceivedTouchIconUrl(WebView view, String url, boolean precomposed);\n    }\n\n    public static class JavascriptInterface {\n        private final LuaObject luaObject;\n\n        public JavascriptInterface(LuaObject luaObject) {\n            this.luaObject = luaObject;\n        }\n\n        @android.webkit.JavascriptInterface\n        public void call(String json) {\n            try {\n                luaObject.call(json);\n            } catch (LuaException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public class LuaWebViewClient extends WebViewClient {\n        @Override\n        public boolean shouldOverrideUrlLoading(WebView view, String url) {\n            if (url.startsWith(\"hydrogen://\")) {\n                Intent intent = new Intent();\n                intent.setAction(Intent.ACTION_VIEW);\n                intent.addCategory(Intent.CATEGORY_BROWSABLE);\n                intent.addCategory(Intent.CATEGORY_DEFAULT);\n                intent.setData(Uri.parse(url));\n                if (intent.resolveActivity(view.getContext().getPackageManager()) != null) {\n                    view.getContext().startActivity(intent);\n                }\n                return true;\n            }\n            return super.shouldOverrideUrlLoading(view, url);\n        }\n\n        @Override\n        public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {\n            try {\n                Context context = getContext();\n                if (context == null || !(context instanceof Activity)) {\n                    super.onReceivedSslError(view, handler, error);\n                    return;\n                }\n                new AlertDialog.Builder(context)\n                        .setMessage(\"error ssl cert invalid\")\n                        .setPositiveButton(\"continue\", new DialogInterface.OnClickListener() {\n                            @Override\n                            public void onClick(DialogInterface dialog, int which) {\n                                handler.proceed();\n                            }\n                        }).setNegativeButton(\"cancel\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        handler.cancel();\n                    }\n                }).show();\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n\n        @Override\n        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {\n\n            if (webViewClientListener != null) {\n                return webViewClientListener.shouldOverrideUrlLoading(view, request);\n            }\n            return super.shouldOverrideUrlLoading(view, request);\n        }\n\n        @Override\n        public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {\n            return super.shouldOverrideKeyEvent(view, event);\n        }\n\n        @Override\n        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {\n            handler.proceed(host.trim(), realm.trim());\n        }\n\n        @Override\n        public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {\n            super.onReceivedHttpError(view, request, errorResponse);\n        }\n\n        @Override\n        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {\n            if (webViewClientListener != null) {\n                return webViewClientListener.shouldInterceptRequest(view, request);\n            }\n            return super.shouldInterceptRequest(view, request);\n        }\n\n        @Override\n        public void onPageFinished(WebView view, String url) {\n            if (webViewClientListener != null) {\n                webViewClientListener.onPageFinished(view, url);\n            }\n            super.onPageFinished(view, url);\n        }\n\n        @Override\n        public void onPageStarted(WebView view, String url, Bitmap favicon) {\n            if (webViewClientListener != null) {\n                webViewClientListener.onPageStarted(view, url, favicon);\n            }\n            super.onPageStarted(view, url, favicon);\n        }\n\n        @Override\n        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {\n            if (webViewClientListener != null) {\n                webViewClientListener.onReceivedError(view, request, error);\n            }\n            super.onReceivedError(view, request, error);\n        }\n    }\n\n    public class LuaWebChromeClient extends WebChromeClient {\n\n        @Override\n        public void onProgressChanged(WebView view, int newProgress) {\n            if (webChromeClientListener != null) {\n                webChromeClientListener.onProgressChanged(view, newProgress);\n            }\n            super.onProgressChanged(view, newProgress);\n        }\n\n        @Override\n        public void onReceivedTitle(WebView view, String title) {\n            if (webChromeClientListener != null) {\n                webChromeClientListener.onReceivedTitle(view, title);\n            }\n            super.onReceivedTitle(view, title);\n        }\n\n        @Override\n        public void onReceivedIcon(WebView view, Bitmap icon) {\n            if (webChromeClientListener != null) {\n                webChromeClientListener.onReceivedIcon(view, icon);\n            }\n            super.onReceivedIcon(view, icon);\n        }\n\n        @Override\n        public void onReceivedTouchIconUrl(WebView view, String url, boolean precomposed) {\n            if (webChromeClientListener != null) {\n                webChromeClientListener.onReceivedTouchIconUrl(view, url, precomposed);\n            }\n            super.onReceivedTouchIconUrl(view, url, precomposed);\n        }\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/NineBitmapDrawable.java",
    "content": "package androlua;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.ColorFilter;\nimport android.graphics.Paint;\nimport android.graphics.PixelFormat;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\n\nimport java.io.IOException;\n\npublic class NineBitmapDrawable extends Drawable {\n    private Paint mPaint = new Paint();\n    private Bitmap mBitmap;\n\n    private int mX1;\n    private int mY1;\n    private int mX2;\n    private int mY2;\n\n    private Rect mRect1;\n    private Rect mRect2;\n    private Rect mRect3;\n\n    private Rect mRect4;\n    private Rect mRect5;\n    private Rect mRect6;\n\n    private Rect mRect7;\n    private Rect mRect8;\n    private Rect mRect9;\n\n    public NineBitmapDrawable(String path) throws IOException {\n        this(LuaBitmap.getLoacalBitmap(path));\n    }\n\n    public NineBitmapDrawable(Bitmap bitmap) {\n        int w = bitmap.getWidth();\n        int h = bitmap.getHeight();\n        int c = Color.BLACK;\n        int x1 = 0;\n        int x2 = 0;\n        for (int i = 0; i < w; i++) {\n            if (bitmap.getPixel(i, 0) == c) {\n                x1 = i;\n                break;\n            }\n        }\n        if (x1 == 0 || x1 == w - 1)\n            throw new IllegalArgumentException(\"not found x1\");\n        for (int i = x1; i < w; i++) {\n            if (bitmap.getPixel(i, 0) != c) {\n                x2 = w - i;\n                break;\n            }\n        }\n        if (x2 == 0 || x2 == 1)\n            throw new IllegalArgumentException(\"not found x2\");\n\n        int y1 = 0;\n        int y2 = 0;\n        for (int i = 0; i < h; i++) {\n            if (bitmap.getPixel(0, i) == c) {\n                y1 = i;\n                break;\n            }\n        }\n        if (y1 == 0 || y1 == h - 1)\n            throw new IllegalArgumentException(\"not found y1\");\n        for (int i = y1; i < h; i++) {\n            if (bitmap.getPixel(0, i) != c) {\n                y2 = h - i;\n                break;\n            }\n        }\n        if (y2 == 0 || y2 == 1)\n            throw new IllegalArgumentException(\"not found y2\");\n\n        init(bitmap, x1, y1, x2, y2);\n    }\n\n\n    public NineBitmapDrawable(Bitmap bitmap, int x1, int y1, int x2, int y2) {\n        init(bitmap, x1, y1, x2, y2);\n    }\n\n    private void init(Bitmap bitmap, int x1, int y1, int x2, int y2) {\n        mBitmap = bitmap;\n        int w = bitmap.getWidth();\n        int h = bitmap.getHeight();\n\n        mX1 = x1;\n        mY1 = y1;\n        mX2 = x2;\n        mY2 = y2;\n\n        x2 = w - x2;\n        y2 = h - y2;\n        mRect1 = new Rect(1, 1, x1, y1);\n        mRect2 = new Rect(x1, 1, x2, y1);\n        mRect3 = new Rect(x2, 1, w - 1, y1);\n\n        mRect4 = new Rect(1, y1, x1, y2);\n        mRect5 = new Rect(x1, y1, x2, y2);\n        mRect6 = new Rect(x2, y1, w - 1, y2);\n\n        mRect7 = new Rect(1, y2, x1, h - 1);\n        mRect8 = new Rect(x1, y2, x2, h - 1);\n        mRect9 = new Rect(x2, y2, w - 1, h - 1);\n    }\n\n    @Override\n    public void draw(Canvas canvas) {\n\n        Rect rect = getBounds();\n        int w = rect.right;\n        int h = rect.bottom;\n\n        Rect rect1 = new Rect(0, 0, mX1, mY1);\n        Rect rect2 = new Rect(mX1, 0, w - mX2, mY1);\n        Rect rect3 = new Rect(w - mX2, 0, w, mY1);\n\n        Rect rect4 = new Rect(0, mY1, mX1, h - mY2);\n        Rect rect5 = new Rect(mX1, mY1, w - mX2, h - mY2);\n        Rect rect6 = new Rect(w - mX2, mY1, w, h - mY2);\n\n        Rect rect7 = new Rect(0, h - mY2, mX1, h);\n        Rect rect8 = new Rect(mX1, h - mY2, w - mX2, h);\n        Rect rect9 = new Rect(w - mX2, h - mY2, w, h);\n\n        canvas.drawBitmap(mBitmap, mRect1, rect1, mPaint);\n        canvas.drawBitmap(mBitmap, mRect2, rect2, mPaint);\n        canvas.drawBitmap(mBitmap, mRect3, rect3, mPaint);\n\n        canvas.drawBitmap(mBitmap, mRect4, rect4, mPaint);\n        canvas.drawBitmap(mBitmap, mRect5, rect5, mPaint);\n        canvas.drawBitmap(mBitmap, mRect6, rect6, mPaint);\n\n        canvas.drawBitmap(mBitmap, mRect7, rect7, mPaint);\n        canvas.drawBitmap(mBitmap, mRect8, rect8, mPaint);\n        canvas.drawBitmap(mBitmap, mRect9, rect9, mPaint);\n    }\n\n    @Override\n    public void setAlpha(int p1) {\n        mPaint.setAlpha(p1);\n    }\n\n    @Override\n    public void setColorFilter(ColorFilter p1) {\n        mPaint.setColorFilter(p1);\n    }\n\n    @Override\n    public int getOpacity() {\n        return PixelFormat.UNKNOWN;\n    }\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/adapter/LuaFragmentPageAdapter.java",
    "content": "package androlua.adapter;\n\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentPagerAdapter;\n\n/**\n * Created by hanks on 2017/5/26. Copyright (C) 2017 Hanks\n */\n\npublic class LuaFragmentPageAdapter extends FragmentPagerAdapter {\n\n    private AdapterCreator creator;\n\n    public LuaFragmentPageAdapter(FragmentManager fm, AdapterCreator creator) {\n        super(fm);\n        this.creator = creator;\n    }\n\n    @Override\n    public Fragment getItem(int position) {\n        return creator.getItem(position);\n    }\n\n    @Override\n    public int getCount() {\n        return (int) creator.getCount();\n    }\n\n    @Override\n    public CharSequence getPageTitle(int position) {\n        return creator.getPageTitle(position);\n    }\n\n    public interface AdapterCreator {\n        long getCount();\n\n        Fragment getItem(int position);\n\n        String getPageTitle(int position);\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/adapter/LuaPagerAdapter.java",
    "content": "package androlua.adapter;\n\nimport android.support.v4.view.PagerAdapter;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.luajava.LuaTable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * adapter for viewpager\n * Created by hanks on 2017/5/13.\n */\n\npublic class LuaPagerAdapter extends PagerAdapter {\n\n    public List<View> mListViews = new ArrayList<>();\n\n    public LuaPagerAdapter(LuaTable luaTable) {\n        addViews(luaTable);\n    }\n\n    public void addViews(LuaTable luaTable) {\n        if (luaTable == null) {\n            return;\n        }\n        int size = luaTable.keySet().size();\n        for (int i = 1; i <= size; i++) {\n            Object v = luaTable.get(i);\n            if (v != null && v instanceof View) {\n                mListViews.add((View) v);\n            }\n        }\n    }\n\n    @Override\n    public int getCount() {\n        return mListViews != null ? mListViews.size() : 0;\n    }\n\n    @Override\n    public boolean isViewFromObject(View view, Object object) {\n        return view == object;\n    }\n\n    @Override\n    public Object instantiateItem(ViewGroup container, int position) {\n        View view = mListViews.get(position);\n        container.addView(view);\n        return view;\n    }\n\n    @Override\n    public void destroyItem(ViewGroup container, int position, Object object) {\n        container.removeView((View) object);\n    }\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/adapter/LuaRecyclerAdapter.java",
    "content": "package androlua.adapter;\n\nimport android.support.v7.widget.RecyclerView;\nimport android.view.ViewGroup;\n\n/**\n * Created by hanks on 2017/5/31. Copyright (C) 2017 Hanks\n */\n\npublic class LuaRecyclerAdapter extends RecyclerView.Adapter {\n\n    AdapterCreator adapterCreator;\n\n    public LuaRecyclerAdapter(AdapterCreator adapterCreator) {\n        this.adapterCreator = adapterCreator;\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        return adapterCreator.onCreateViewHolder(parent, viewType);\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {\n        adapterCreator.onBindViewHolder(holder, position);\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return (int) adapterCreator.getItemViewType(position);\n    }\n\n    @Override\n    public int getItemCount() {\n        return (int) adapterCreator.getItemCount();\n    }\n\n    public interface AdapterCreator {\n        RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType);\n\n        void onBindViewHolder(RecyclerView.ViewHolder holder, int position);\n\n        long getItemViewType(int position);\n\n        long getItemCount();\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/adapter/LuaRecyclerHolder.java",
    "content": "package androlua.adapter;\n\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\n\n/**\n * Created by hanks on 2017/5/31. Copyright (C) 2017 Hanks\n */\n\npublic class LuaRecyclerHolder extends RecyclerView.ViewHolder {\n    public LuaRecyclerHolder(View itemView) {\n        super(itemView);\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/base/BaseActivity.java",
    "content": "package androlua.base;\n\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.view.View;\n\nimport androlua.widget.statusbar.StatusBarView;\nimport androlua.widget.swipebacklayout.app.SwipeBackActivity;\nimport pub.hanks.luajandroid.R;\n\n/**\n * Created by hanks on 2017/6/2. Copyright (C) 2017 Hanks\n */\n\npublic class BaseActivity extends SwipeBackActivity {\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if (Build.VERSION.SDK_INT >= 21) {\n            View decorView = getWindow().getDecorView();\n            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN\n                    | View.SYSTEM_UI_FLAG_IMMERSIVE\n                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;\n            decorView.setSystemUiVisibility(option);\n            getWindow().setStatusBarColor(Color.TRANSPARENT);\n        }\n    }\n\n    public void setStatusBarColor(int color) {\n        View statusbar = findViewById(R.id.view_statusbar);\n        if (statusbar != null && statusbar instanceof StatusBarView) {\n            ((StatusBarView) statusbar).setStatusBarColor(color);\n            return;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            getWindow().setStatusBarColor(color);\n        }\n    }\n\n    public void setLightStatusBar() {\n        if (Build.VERSION.SDK_INT >= 23) {\n            View decorView = getWindow().getDecorView();\n            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN\n                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE\n                    | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;\n            decorView.setSystemUiVisibility(option);\n            setStatusBarColor(0xFFFFFFFF);\n        } else if (Build.VERSION.SDK_INT >= 21) {\n            setStatusBarColor(0x33000000);\n        }\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/base/BaseFragment.java",
    "content": "package androlua.base;\n\nimport android.support.v4.app.Fragment;\n\n/**\n * Created by hanks on 2017/6/2. Copyright (C) 2017 Hanks\n */\n\npublic class BaseFragment extends Fragment {\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/common/LuaConstants.java",
    "content": "package androlua.common;\n\n/**\n * Created by hanks on 2017/6/19.\n */\n\npublic class LuaConstants {\n    public static final String KEY_VERSION = \"key_version\";\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/common/LuaFileUtils.java",
    "content": "package androlua.common;\n\nimport android.content.Context;\nimport android.content.res.AssetManager;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.os.Environment;\nimport android.support.annotation.NonNull;\nimport android.view.View;\n\nimport com.luajava.LuaObject;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.BufferedOutputStream;\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\nimport java.util.zip.ZipOutputStream;\n\nimport androlua.LuaHttp;\nimport androlua.LuaManager;\nimport androlua.plugin.Plugin;\n\nimport static android.graphics.Bitmap.CompressFormat.JPEG;\nimport static android.graphics.Bitmap.CompressFormat.PNG;\n\n/**\n * LuaFileUtils\n * Created by hanks on 16/6/28.\n */\npublic class LuaFileUtils {\n\n    // 缓存文件头信息-文件头信息\n    public static final HashMap<String, String> mFileTypes = new HashMap<>();\n    private static final String APP_DIR = \"LLLLLua\";\n    // 32k 缩略图的限制，所以采用 RGB_565 比较小\n    private static final Bitmap.Config CONFIG = Bitmap.Config.RGB_565;\n\n    static {\n        // images\n        mFileTypes.put(\"FFD8FFE1\", \"jpg\");\n        mFileTypes.put(\"FFD8FFE0\", \"jpg\");\n        mFileTypes.put(\"FFD8\", \"jpg\");\n        mFileTypes.put(\"89504E47\", \"png\");\n        mFileTypes.put(\"47494638\", \"gif\");\n        mFileTypes.put(\"49492A00\", \"tif\");\n        mFileTypes.put(\"424D\", \"bmp\");\n        //\n        mFileTypes.put(\"41433130\", \"dwg\"); // CAD\n        mFileTypes.put(\"38425053\", \"psd\");\n        mFileTypes.put(\"7B5C727466\", \"rtf\"); // 日记本\n        mFileTypes.put(\"3C3F786D6C\", \"xml\");\n        mFileTypes.put(\"68746D6C3E\", \"html\");\n        mFileTypes.put(\"44656C69766572792D646174653A\", \"eml\"); // 邮件\n        mFileTypes.put(\"D0CF11E0\", \"doc\");\n        mFileTypes.put(\"5374616E64617264204A\", \"mdb\");\n        mFileTypes.put(\"252150532D41646F6265\", \"ps\");\n        mFileTypes.put(\"255044462D312E\", \"pdf\");\n        mFileTypes.put(\"504B0304\", \"docx\");\n        mFileTypes.put(\"52617221\", \"rar\");\n        mFileTypes.put(\"57415645\", \"wav\");\n        mFileTypes.put(\"41564920\", \"avi\");\n        mFileTypes.put(\"2E524D46\", \"rm\");\n        mFileTypes.put(\"000001BA\", \"mpg\");\n        mFileTypes.put(\"000001B3\", \"mpg\");\n        mFileTypes.put(\"6D6F6F76\", \"mov\");\n        mFileTypes.put(\"3026B2758E66CF11\", \"asf\");\n        mFileTypes.put(\"4D546864\", \"mid\");\n        mFileTypes.put(\"1F8B08\", \"gz\");\n        mFileTypes.put(\"4D5A9000\", \"exe/dll\");\n        mFileTypes.put(\"75736167\", \"txt\");\n    }\n\n    private static Context getContext() {\n        return LuaManager.getInstance().getContext();\n    }\n\n    /**\n     * 根据文件路径获取文件头信息\n     *\n     * @param filePath 文件路径\n     * @return 文件头信息\n     */\n    public static String getFileType(String filePath) {\n        String fileHeader = getFileHeader(filePath);\n        if (LuaStringUtils.isEmpty(fileHeader) || fileHeader.startsWith(\"FFD8\")) {\n            return \"jpg\";\n        }\n        return mFileTypes.get(fileHeader);\n    }\n\n    /**\n     * 根据文件路径获取文件头信息\n     *\n     * @param filePath 文件路径\n     * @return 文件头信息\n     */\n    public static String getFileHeader(String filePath) {\n        FileInputStream is = null;\n        String value = null;\n        try {\n            is = new FileInputStream(filePath);\n            byte[] b = new byte[4];\n            /*\n             * int read() 从此输入流中读取一个数据字节。 int read(byte[] b) 从此输入流中将最多 b.length\n             * 个字节的数据读入一个 byte 数组中。 int read(byte[] b, int off, int len)\n             * 从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。\n             */\n            is.read(b, 0, b.length);\n            value = bytesToHexString(b);\n        } catch (Exception e) {\n        } finally {\n            if (null != is) {\n                try {\n                    is.close();\n                } catch (IOException e) {\n                }\n            }\n        }\n        return value;\n    }\n    /**\n     * 将要读取文件头信息的文件的byte数组转换成string类型表示\n     *\n     * @param src 要读取文件头信息的文件的byte数组\n     * @return 文件头信息\n     */\n    private static String bytesToHexString(byte[] src) {\n        StringBuilder builder = new StringBuilder();\n        if (src == null || src.length <= 0) {\n            return null;\n        }\n        String hv;\n        for (int i = 0; i < src.length; i++) {\n            // 以十六进制（基数 16）无符号整数形式返回一个整数参数的字符串表示形式，并转换为大写\n            hv = Integer.toHexString(src[i] & 0xFF).toUpperCase();\n            if (hv.length() < 2) {\n                builder.append(0);\n            }\n            builder.append(hv);\n        }\n        return builder.toString();\n    }\n\n\n    public static void downloadPlugin(final String url, final String pluginName, final LuaObject callback) {\n        new Thread() {\n            @Override\n            public void run() {\n                super.run();\n                try {\n                    String destDirectory = getPluginsDir() + \"/\" + pluginName;\n                    String savePath = destDirectory + \".zip\";\n                    LuaHttp.downloadFile(url, savePath);\n                    LuaFileUtils.unzip(savePath, getPluginsDir());\n                    deleteFileOrDir(new File(savePath));\n                    callback.call(destDirectory);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        }.start();\n    }\n\n    public static void downloadLuaFile(final String url, final LuaObject callback) {\n        new Thread() {\n            @Override\n            public void run() {\n                super.run();\n                try {\n                    String destDirectory = LuaManager.getInstance().getLuaExtDir() + \"/lua\";\n                    String savePath = destDirectory + \".zip\";\n                    LuaHttp.downloadFile(url, savePath);\n                    LuaFileUtils.unzip(savePath, LuaManager.getInstance().getLuaExtDir());\n                    deleteFileOrDir(new File(savePath));\n                    if (callback != null) callback.call(destDirectory);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        }.start();\n    }\n\n    public static void deleteFileOrDir(File file) {\n        if (file == null || !file.exists()) {\n            return;\n        }\n        if (!file.isDirectory()) {\n            file.delete();\n            return;\n        }\n        File[] files = file.listFiles();\n        if (files == null) {\n            return;\n        }\n        for (File f : files) {\n            deleteFileOrDir(f);\n        }\n        file.delete();\n    }\n\n    public static void removePlugin(String pluginId) {\n        for (Plugin plugin : getPluginList()) {\n            if (pluginId.equals(plugin.getId())) {\n                File file = new File(plugin.getPath());\n                deleteFileOrDir(file);\n            }\n        }\n    }\n\n    public static String getPluginsDir() {\n        return getAndroLuaDir();\n    }\n\n    public static List<Plugin> getPluginList() {\n        // 读取总目录\n        File pluginDir = new File(getPluginsDir());\n        if (!pluginDir.exists()) {\n            return Collections.emptyList();\n        }\n        List<Plugin> pluginList = new ArrayList<>();\n        for (File file : pluginDir.listFiles()) {\n            // 读取单个插件文件\n            Plugin plugin = parsePluginInfo(file);\n            if (plugin == null) {\n                continue;\n            }\n            pluginList.add(plugin);\n        }\n        Collections.sort(pluginList, new Comparator<Plugin>() {\n            @Override\n            public int compare(Plugin o1, Plugin o2) {\n                return (int) (o1.getUpdateAt() - o2.getUpdateAt());\n            }\n        });\n        return pluginList;\n    }\n\n    // 解析插件\n    private static Plugin parsePluginInfo(File pluginDir) {\n        if (pluginDir == null || !pluginDir.isDirectory()) {\n            return null;\n        }\n        File info = null;\n        for (File pFile : pluginDir.listFiles()) {\n            if (\"info.json\".equals(pFile.getName())) {\n                info = pFile;\n            }\n        }\n        if (info == null) {\n            return null;\n        }\n\n        String str = file2String(info);\n        try {\n            Plugin plugin = new Plugin();\n            plugin.setUpdateAt(info.lastModified());\n            JSONObject jsonObject = new JSONObject(str);\n            plugin.setPath(pluginDir.getAbsolutePath());\n            plugin.setPlugin(true);\n            plugin.setId(jsonObject.getString(\"id\"));\n            plugin.setName(jsonObject.getString(\"name\"));\n            plugin.setIconPath(jsonObject.getString(\"icon\"));\n            plugin.setMainPath(jsonObject.getString(\"main\"));\n            plugin.setVersionName(jsonObject.getString(\"versionName\"));\n            plugin.setVersionCode(jsonObject.getInt(\"versionCode\"));\n            return plugin;\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public static void copyAssetsFlies(String assetDir, String outputDir) {\n        try {\n            String[] files = getContext().getAssets().list(assetDir);\n            if (files == null) {\n                return;\n            }\n            for (String file : files) {\n                copyFile(getContext().getAssets().open(assetDir + \"/\" + file), outputDir + \"/\" + file);\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n\n    public static void copyFile(InputStream inStream, String newPath) throws IOException {\n        int len;\n        FileOutputStream fs = new FileOutputStream(newPath);\n        byte[] buffer = new byte[4096];\n        while ((len = inStream.read(buffer)) != -1) {\n            fs.write(buffer, 0, len);\n        }\n        inStream.close();\n    }\n\n\n    private static String file2String(File file) {\n        BufferedReader br = null;\n        try {\n            br = new BufferedReader(new FileReader(file));\n            StringBuilder sb = new StringBuilder();\n            String line = br.readLine();\n            while (line != null) {\n                sb.append(line);\n                sb.append(\"\\n\");\n                line = br.readLine();\n            }\n            return sb.toString();\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                if (br != null) br.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return \"\";\n    }\n\n    public static File convertViewToImage(View view, @NonNull String filePath) throws Exception {\n        if (view.getWidth() == 0 || view.getHeight() == 0) {\n            throw new Exception(\"width or height must not be 0\");\n        }\n\n        if (view.getHeight() > 100000) {\n            throw new Exception(\"must small\");\n        }\n\n        final File saveFile = new File(filePath);\n        Bitmap createBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);\n        Canvas canvas = new Canvas(createBitmap);\n        canvas.save();\n        view.draw(canvas);\n        canvas.restore();\n        String imageType = createBitmap.getHeight() > 20000 ? \"jpg\" : \"png\";\n        Bitmap.CompressFormat compressFormat = \"jpg\".equals(imageType) ? PNG : JPEG;\n        bitmapToFile(createBitmap, saveFile, compressFormat, \"jpg\".equals(imageType) ? 90 : 100);\n        if (createBitmap != null) {\n            createBitmap.recycle();\n        }\n        canvas.setBitmap(null);\n        System.gc();\n        return saveFile;\n    }\n\n    public static File bitmapToFile(Bitmap bitmap, File file, Bitmap.CompressFormat compressFormat, int quality) {\n        if (file == null) {\n            return null;\n        }\n        FileOutputStream fileOutputStream = null;\n        try {\n            fileOutputStream = new FileOutputStream(file);\n            bitmap.compress(compressFormat, quality, fileOutputStream);\n            fileOutputStream.flush();\n            fileOutputStream.close();\n            return file;\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        } finally {\n            try {\n                if (fileOutputStream != null) fileOutputStream.close();\n            } catch (IOException e22) {\n                e22.printStackTrace();\n            }\n        }\n    }\n\n    public static String saveImage(String imagePath) {\n        File file = new File(imagePath);\n        if (!file.exists()) {\n            return null;\n        }\n        try {\n            String fileName = System.currentTimeMillis() + \".png\";\n            String outputPath = getProjectImagePath();\n            //create output directory if it doesn't exist\n            File dir = new File(outputPath);\n            if (!dir.exists()) {\n                dir.mkdirs();\n            }\n            InputStream in = new FileInputStream(imagePath);\n            OutputStream out = new FileOutputStream(outputPath + \"/\" + fileName);\n            byte[] buffer = new byte[1024];\n            int read;\n            while ((read = in.read(buffer)) != -1) {\n                out.write(buffer, 0, read);\n            }\n            in.close();\n            // write the output file (You have now copied the file)\n            out.flush();\n            out.close();\n            return fileName;\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    public static String getImagePath(String name) {\n        return getProjectImagePath() + \"/\" + name;\n    }\n\n    public static String getPublicPicturePath(String fileName) {\n        // Get the directory for the user's public pictures directory.\n        File file = new File(Environment.getExternalStoragePublicDirectory(\n                Environment.DIRECTORY_PICTURES), APP_DIR);\n        if (!file.mkdirs()) {\n            LuaLog.e(\"Directory not created\");\n        }\n        return file.getAbsolutePath() + \"/\" + fileName;\n    }\n\n    public static Bitmap getBitmapFromFile(String name) {\n        String filePath = getProjectImagePath() + \"/\" + name;\n        return BitmapFactory.decodeFile(filePath);\n    }\n\n    public static void makeDefaultCSSFile() {\n        String path = getProjectCSSPath() + \"/marked.css\";\n        File file = new File(path);\n        if (!file.exists()) {\n            makeDefaultCSSFile(path);\n        }\n    }\n\n    private static void makeDefaultCSSFile(String path) {\n        try {\n            InputStream inputStream = getContext().getResources().getAssets().open(\"marked.css\");\n            saveToFile(inputStream, path);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static String convertStreamToString(InputStream is) {\n        BufferedReader br = null;\n        StringBuilder sb = new StringBuilder();\n        String line;\n        try {\n            br = new BufferedReader(new InputStreamReader(is));\n            while ((line = br.readLine()) != null) {\n                sb.append(line);\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            if (br != null) {\n                try {\n                    br.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n        return sb.toString();\n    }\n\n    public static String getProjectCSSPath() {\n        return insureDirExists(getProjectPath() + \"/css\");\n    }\n\n    public static String getBackupPath() {\n        return insureDirExists(getProjectPath() + \"/backup\");\n    }\n\n    public static String getBackupNotePath() {\n        return insureDirExists(getProjectPath() + \"/notejson\");\n    }\n\n    private static String insureDirExists(String dir) {\n        File file = new File(dir);\n        if (!file.exists()) {\n            file.mkdirs();\n        }\n        return file.getAbsolutePath();\n    }\n\n    public static String getProjectImagePath() {\n        String path = getProjectPath() + \"/images\";\n        insureDirExists(path);\n        File noMediaFile = new File(path, \".nomedia\");\n        if (!noMediaFile.exists()) {\n            try {\n                noMediaFile.createNewFile();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return path;\n    }\n\n    public static String getProjectPath() {\n        String downloadDir = getContext().getExternalFilesDir(APP_DIR).getAbsolutePath();\n        String filePath = downloadDir;\n        File file = new File(filePath);\n        if (!file.exists()) {\n            file.mkdirs();\n        }\n        return filePath;\n    }\n\n    public static boolean sdCardAvaible() {\n        return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());\n    }\n\n\n    public static String saveToFile(InputStream in, String filePath) {\n        try {\n            FileOutputStream out = new FileOutputStream(filePath);\n            byte[] buffer = new byte[1024];\n            int read;\n            while ((read = in.read(buffer)) != -1) {\n                out.write(buffer, 0, read);\n            }\n            in.close();\n            out.flush();\n            out.close();\n            return filePath;\n        } catch (Exception e) {\n            e.printStackTrace();\n            return filePath;\n        }\n    }\n\n    public static String saveToFile(String txt, String filePath) {\n        try {\n            File file = new File(filePath);\n            if (!file.exists()) {\n                file.getParentFile().mkdirs();\n                file.createNewFile();\n            }\n            FileWriter fooWriter = new FileWriter(file, false); // true to append // false to overwrite.\n            fooWriter.write(txt);\n            fooWriter.close();\n            return file.getAbsolutePath();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return txt;\n    }\n\n    public static String getFontPath(String fontAlias) {\n        String path = getProjectPath() + File.separator + \"font\";\n        File dir = new File(path);\n        if (!dir.exists()) {\n            dir.mkdirs();\n        }\n        return (dir + File.separator + fontAlias).toLowerCase();\n    }\n\n    /**\n     * Extracts a zip file specified by the zipFilePath to a directory specified by\n     * destDirectory (will be created if does not exists)\n     *\n     * @param zipFilePath\n     * @param destDirectory\n     * @throws IOException\n     */\n    public static void unzip(String zipFilePath, String destDirectory) throws IOException {\n        File destDir = new File(destDirectory);\n        if (!destDir.exists()) {\n            destDir.mkdir();\n        }\n        ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath));\n        ZipEntry entry = zipIn.getNextEntry();\n        // iterates over entries in the zip file\n        while (entry != null) {\n            String filePath = (destDirectory + File.separator + entry.getName()).toLowerCase();\n            if (!entry.isDirectory()) {\n                // if the entry is a file, extracts it\n                extractFile(zipIn, filePath);\n            } else {\n                // if the entry is a directory, make the directory\n                File dir = new File(filePath);\n                dir.mkdir();\n            }\n            zipIn.closeEntry();\n            entry = zipIn.getNextEntry();\n        }\n        zipIn.close();\n    }\n\n    /**\n     * Extracts a zip entry (file entry)\n     *\n     * @param zipIn\n     * @param filePath\n     * @throws IOException\n     */\n    private static void extractFile(ZipInputStream zipIn, String filePath) throws IOException {\n        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));\n        byte[] bytesIn = new byte[2048];\n        int read = 0;\n        while ((read = zipIn.read(bytesIn)) != -1) {\n            bos.write(bytesIn, 0, read);\n        }\n        bos.close();\n    }\n\n    public static void rewriteFile(File file, String content) {\n        BufferedWriter bw = null;\n        FileWriter fw = null;\n\n        try {\n            fw = new FileWriter(file);\n            bw = new BufferedWriter(fw);\n            bw.write(content);\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                if (bw != null)\n                    bw.close();\n                if (fw != null)\n                    fw.close();\n            } catch (IOException ex) {\n                ex.printStackTrace();\n            }\n        }\n    }\n\n    public static String getFileContent(File file) {\n        BufferedReader br = null;\n        try {\n            br = new BufferedReader(new FileReader(file));\n            StringBuilder sb = new StringBuilder();\n            String line = br.readLine();\n\n            while (line != null) {\n                sb.append(line);\n                sb.append(\"\\n\");\n                line = br.readLine();\n            }\n            return sb.toString();\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                if (br != null) br.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return null;\n    }\n\n    public static void deleteFile(String path) {\n        File file = new File(path);\n        if (file.exists()) {\n            file.delete();\n        }\n    }\n\n    public static void deleteDir(String dirPath) {\n        File dir = new File(dirPath);\n        if (!dir.exists()) {\n            return;\n        }\n        if (dir.isDirectory()) {\n            if (dir.listFiles() == null) {\n                dir.delete();\n                return;\n            }\n            for (File file : dir.listFiles()) {\n                deleteDir(file.getAbsolutePath());\n            }\n        } else {\n            dir.delete();\n        }\n    }\n\n    public static void writeZip(File file, String parentPath, ZipOutputStream zos) {\n        if (file.exists()) {\n            if (file.isDirectory()) {//处理文件夹\n                parentPath += file.getName() + File.separator;\n                File[] files = file.listFiles();\n                if (files == null) {\n                    return;\n                }\n                for (File f : files) {\n                    writeZip(f, parentPath, zos);\n                }\n            } else {\n                FileInputStream fis = null;\n                try {\n                    fis = new FileInputStream(file);\n                    ZipEntry ze = new ZipEntry(parentPath + file.getName());\n                    zos.putNextEntry(ze);\n                    byte[] content = new byte[1024];\n                    int len;\n                    while ((len = fis.read(content)) != -1) {\n                        zos.write(content, 0, len);\n                        zos.flush();\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                } finally {\n                    try {\n                        if (fis != null) {\n                            fis.close();\n                        }\n                    } catch (IOException e) {\n                        e.printStackTrace();\n                    }\n                }\n            }\n        }\n    }\n\n    public static String getAndroLuaDir() {\n        File appDir;\n        if (sdCardAvaible()) {\n            appDir = getContext().getExternalFilesDir(APP_DIR);\n        } else {\n            appDir = new File(getContext().getFilesDir(), APP_DIR);\n        }\n        appDir.mkdirs(); // dont need judge dir exits\n\n        return appDir.getAbsolutePath();\n    }\n\n    public static byte[] readAsset(String name) throws IOException {\n        AssetManager am = getContext().getAssets();\n        InputStream is = am.open(name);\n        byte[] ret = readAll(is);\n        is.close();\n        //am.close();\n        return ret;\n    }\n\n    private static byte[] readAll(InputStream input) throws IOException {\n        ByteArrayOutputStream output = new ByteArrayOutputStream(4096);\n        byte[] buffer = new byte[4096];\n        int n = 0;\n        while (-1 != (n = input.read(buffer))) {\n            output.write(buffer, 0, n);\n        }\n        byte[] ret = output.toByteArray();\n        output.close();\n        return ret;\n    }\n\n    //复制asset文件到sd卡\n    public static void assetsToSD(String InFileName, String OutFileName) throws IOException {\n        InputStream myInput;\n        OutputStream myOutput = new FileOutputStream(OutFileName);\n        myInput = getContext().getAssets().open(InFileName);\n        byte[] buffer = new byte[8192];\n        int length = myInput.read(buffer);\n        while (length > 0) {\n            myOutput.write(buffer, 0, length);\n            length = myInput.read(buffer);\n        }\n\n        myOutput.flush();\n        myInput.close();\n        myOutput.close();\n    }\n\n    /**\n     * 解压Assets中的文件\n     */\n    public static void unZipAssets(String assetName, String outputDirectory) throws IOException {\n        //创建解压目标目录\n        File file = new File(outputDirectory);\n        //如果目标目录不存在，则创建\n        if (!file.exists()) {\n            file.mkdirs();\n        }\n        InputStream inputStream = null;\n        //打开压缩文件\n        try {\n            inputStream = getContext().getAssets().open(assetName);\n        } catch (IOException e) {\n            return;\n        }\n\n        ZipInputStream zipInputStream = new ZipInputStream(inputStream);\n        //读取一个进入点\n        ZipEntry zipEntry = zipInputStream.getNextEntry();\n        //使用1Mbuffer\n        byte[] buffer = new byte[1024 * 32];\n        //解压时字节计数\n        int count = 0;\n        //如果进入点为空说明已经遍历完所有压缩包中文件和目录\n        while (zipEntry != null) {\n            //如果是一个目录\n            if (zipEntry.isDirectory()) {\n                //String name = zipEntry.getName();\n                //name = name.substring(0, name.length() - 1);\n                file = new File(outputDirectory + File.separator + zipEntry.getName());\n                file.mkdir();\n            } else {\n                //如果是文件\n                file = new File(outputDirectory + File.separator\n                        + zipEntry.getName());\n                //创建该文件\n                file.createNewFile();\n                FileOutputStream fileOutputStream = new FileOutputStream(file);\n                while ((count = zipInputStream.read(buffer)) > 0) {\n                    fileOutputStream.write(buffer, 0, count);\n                }\n                fileOutputStream.close();\n            }\n            //定位到下一个文件入口\n            zipEntry = zipInputStream.getNextEntry();\n        }\n        zipInputStream.close();\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/common/LuaLog.java",
    "content": "package androlua.common;\n\nimport android.util.Log;\n\nimport androlua.LuaManager;\n\n\n/**\n * LuaLog\n * Created by hanks on 2016/11/19.\n */\n\npublic class LuaLog {\n    private static final String TAG = \"LLogs\";\n\n    public static boolean showLog() {\n        return LuaManager.getInstance().isDebugable();\n    }\n\n    public static void i(String s) {\n        if (showLog()) {\n            Log.i(TAG, s == null ? \"null\" : s);\n        }\n    }\n\n    public static void w(String s) {\n        if (showLog()) {\n            Log.w(TAG, s == null ? \"null\" : s);\n        }\n    }\n\n    public static void d(String s) {\n        if (showLog()) {\n            Log.d(TAG, s == null ? \"null\" : s);\n        }\n    }\n\n    public static void e(String s) {\n        if (showLog()) {\n            Log.e(TAG, s == null ? \"null\" : s);\n        }\n    }\n\n    public static void e(Throwable e) {\n        if (showLog() && e != null) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/common/LuaSp.java",
    "content": "package androlua.common;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimport androlua.LuaManager;\n\n/**\n * SharedPreferences\n * Created by hanks on 2017/6/19.\n */\n\npublic class LuaSp {\n\n    private static LuaSp instance;\n    private final SharedPreferences sp;\n\n    public static LuaSp getInstance(String fileName) {\n        if (instance == null) {\n            synchronized (LuaSp.class) {\n                if (instance == null) {\n                    instance = new LuaSp(fileName);\n                }\n            }\n        }\n        return instance;\n    }\n\n    private LuaSp(String fileName) {\n        Context context = LuaManager.getInstance().getContext();\n        sp = context.getSharedPreferences(fileName, Context.MODE_PRIVATE);\n    }\n\n    public void save(String key, Object value) {\n        SharedPreferences.Editor editor = sp.edit();\n        if (value instanceof Boolean) {\n            editor.putBoolean(key, (Boolean) value);\n        } else if (value instanceof String) {\n            editor.putString(key, (String) value);\n        } else if (value instanceof Integer) {\n            editor.putInt(key, (Integer) value);\n        } else if (value instanceof Float) {\n            editor.putFloat(key, (Float) value);\n        } else if (value instanceof Long) {\n            editor.putLong(key, (Long) value);\n        }\n        editor.apply();\n    }\n\n    public <T> T get(String key, T defaultValue) {\n        Object value = null;\n        if (defaultValue instanceof Boolean) {\n            value = sp.getBoolean(key, (Boolean) defaultValue);\n        } else if (defaultValue instanceof String) {\n            value = sp.getString(key, (String) defaultValue);\n        } else if (defaultValue instanceof Float) {\n            value = sp.getFloat(key, (Float) defaultValue);\n        } else if (defaultValue instanceof Long) {\n            value = sp.getLong(key, (Long) defaultValue);\n        } else if (defaultValue instanceof Integer) {\n            value = sp.getInt(key, (Integer) defaultValue);\n        }\n        return (T) value;\n    }\n\n    /**\n     * 移除某个key值已经对应的值\n     */\n    public void remove(String key) {\n        SharedPreferences.Editor editor = sp.edit();\n        editor.remove(key);\n        editor.apply();\n    }\n\n    /**\n     * 是否已经存在该 key\n     */\n    public boolean contains(String key) {\n        return sp.contains(key);\n    }\n\n\n    /**\n     * 清除所有数据\n     */\n    public void clear() {\n        SharedPreferences.Editor editor = sp.edit();\n        editor.clear();\n        editor.apply();\n    }\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/common/LuaStringUtils.java",
    "content": "package androlua.common;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\n/**\n * 字符串处理\n * Created by hanks on 2016/11/29.\n */\n\npublic class LuaStringUtils {\n    public static final String EMPTY_CHAR = \"\\u200B\";\n\n    public static boolean isEmpty(String s) {\n        return s == null || s.length() == 0;\n    }\n\n    // 去除最后一行换行\n    public static String trimEnd(String s) {\n        if (!isEmpty(s) && (s.endsWith(\"\\n\") || s.endsWith(EMPTY_CHAR))) {\n            return s.substring(0, s.length() - 1);\n        } else {\n            return s;\n        }\n    }\n\n    public static boolean isEmptyTrim(String s) {\n        return s == null || s.trim().length() == 0 || EMPTY_CHAR.equals(s);\n    }\n\n    public static String md5(String source) {\n        String target = \"\";\n        if (source == null)\n            source = \"\";\n        try {\n            MessageDigest md = MessageDigest.getInstance(\"MD5\");\n            md.update(source.getBytes());\n            byte b[] = md.digest();\n            int i;\n            StringBuffer buf = new StringBuffer(\"\");\n            for (int offset = 0; offset < b.length; offset++) {\n                i = b[offset];\n                if (i < 0)\n                    i += 256;\n                if (i < 16)\n                    buf.append(\"0\");\n                buf.append(Integer.toHexString(i));\n            }\n            target = buf.toString();\n\n        } catch (NoSuchAlgorithmException e) {\n        }\n        return target;\n    }\n\n    public static boolean isUrl(String str) {\n        return str != null && (str.startsWith(\"http://\") || str.startsWith(\"https://\"));\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/common/LuaToast.java",
    "content": "package androlua.common;\n\nimport android.widget.Toast;\n\nimport androlua.LuaManager;\n\n/**\n * Created by hanks on 2017/6/19.\n */\n\npublic class LuaToast {\n    public static void show(String s) {\n        Toast.makeText(LuaManager.getInstance().getContext(), s, Toast.LENGTH_SHORT).show();\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/fragment/MenuFragment.java",
    "content": "package androlua.fragment;\n\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.drawable.GradientDrawable;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v7.app.AlertDialog;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.EditText;\nimport android.widget.ImageView;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.request.RequestListener;\nimport com.bumptech.glide.request.target.Target;\n\nimport java.io.File;\nimport java.util.List;\n\nimport androlua.LuaActivity;\nimport androlua.LuaManager;\nimport androlua.LuaUtil;\nimport androlua.base.BaseFragment;\nimport androlua.common.LuaFileUtils;\nimport androlua.common.LuaStringUtils;\nimport androlua.plugin.Plugin;\nimport androlua.utils.ShortcutUtils;\nimport jp.wasabeef.glide.transformations.RoundedCornersTransformation;\nimport pub.hanks.luajandroid.R;\n\n/**\n * MenuFragment\n * Created by hanks on 2017/8/22.\n */\n\npublic class MenuFragment extends BaseFragment {\n    public static MenuFragment newInstance() {\n        Bundle args = new Bundle();\n        MenuFragment fragment = new MenuFragment();\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        View view = inflater.inflate(R.layout.fragment_menu, container, false);\n        return view;\n    }\n\n    @Override\n    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        view.findViewById(R.id.add_shortcut).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                if (getActivity() == null || !(getActivity() instanceof LuaActivity)) {\n                    return;\n                }\n\n                Intent intent = getActivity().getIntent();\n                String luaFile = LuaUtil.IntentHelper.getLuaPath(intent);\n                String luaExtDir = LuaManager.getInstance().getLuaExtDir();\n                if (!luaFile.startsWith(\"/\")) {\n                    luaFile = luaExtDir + \"/\" + luaFile;\n                }\n                File file = new File(luaFile);\n                if (!file.exists()) {\n                    return;\n                }\n                String pluginRoot;\n                do {\n                    pluginRoot = file.getAbsolutePath();\n                    file = file.getParentFile();\n                } while (!luaExtDir.equals(file.getAbsolutePath()));\n\n                String name = \"氢-\" + file.getName();\n                Plugin p = null;\n\n                List<Plugin> pluginList = LuaFileUtils.getPluginList();\n                for (Plugin plugin : pluginList) {\n                    if (plugin.getPath().equals(pluginRoot)) {\n                        name = plugin.getName();\n                        p = plugin;\n                        break;\n                    }\n                }\n                if (p != null) {\n                    showAddShortcutDialog(intent, name, p.getIconPath());\n                } else {\n                    showAddShortcutDialog(intent, name, null);\n                }\n            }\n        });\n    }\n\n    private void showAddShortcutDialog(final Intent intent, String name, String iconPath) {\n        if (getActivity() == null || !(getActivity() instanceof LuaActivity)) {\n            return;\n        }\n        ((LuaActivity) getActivity()).closeDrawer();\n        View view = View.inflate(getActivity(), R.layout.dialog_add_shortcut, null);\n        final EditText et_name = (EditText) view.findViewById(R.id.name);\n        final ImageView iv_icon = (ImageView) view.findViewById(R.id.icon);\n        et_name.setText(\"氢 · \" +  name);\n        final Bitmap[] bm = new Bitmap[1];\n        if (!LuaStringUtils.isEmpty(iconPath)) {\n            GradientDrawable gd = new GradientDrawable();\n            gd.setCornerRadius(LuaUtil.dp2px(100));\n            gd.setColor(0xffebf0f2);\n            Glide.with(this)\n                    .load(iconPath)\n                    .asBitmap()\n                    .placeholder(gd)\n                    .transform(new RoundedCornersTransformation(getContext(), LuaUtil.dp2px(100), 0))\n                    .listener(new RequestListener<String, Bitmap>() {\n                        @Override\n                        public boolean onException(Exception e, String model, Target<Bitmap> target, boolean isFirstResource) {\n                            return false;\n                        }\n\n                        @Override\n                        public boolean onResourceReady(Bitmap resource, String model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {\n                            bm[0] = resource;\n                            return false;\n                        }\n                    }).into(iv_icon);\n        }\n        new AlertDialog.Builder(getActivity())\n                .setTitle(\"放到桌面\")\n                .setView(view)\n                .setNegativeButton(\"取消\", null)\n                .setPositiveButton(\"确定\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        String name = et_name.getText().toString();\n                        if (LuaStringUtils.isEmpty(name)) {\n                            name = \" \";\n                        }\n                        if (bm[0] == null) {\n                            bm[0] = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);\n                        }\n                        ShortcutUtils.installShortcut(getActivity(), name, bm[0], intent);\n                    }\n                })\n                .show();\n\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/plugin/Plugin.java",
    "content": "package androlua.plugin;\n\nimport com.luajava.LuaState;\n\nimport androlua.LuaManager;\n\n/**\n * Created by hanks on 2017/5/5. Copyright (C) 2017 Hanks\n */\n\npublic class Plugin {\n    private final LuaManager luaManager;\n    private String path;\n    private String id;\n    private String name;\n    private String iconPath;\n    private String mainPath;\n    private String versionName;\n    private int versionCode;\n    private boolean isPlugin;\n    private long updateAt;\n    private LuaState L;\n\n    public Plugin() {\n        luaManager = LuaManager.getInstance();\n    }\n\n    public boolean isPlugin() {\n        return isPlugin;\n    }\n\n    public void setPlugin(boolean plugin) {\n        isPlugin = plugin;\n    }\n\n    public String getPath() {\n        return path;\n    }\n\n    public void setPath(String path) {\n        this.path = path;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public void setUpdateAt(long updateAt) {\n        this.updateAt = updateAt;\n    }\n\n    public long getUpdateAt() {\n        return updateAt;\n    }\n\n    public String getIconPath() {\n        if (iconPath == null) {\n            return \"http://image.coolapk.com/apk_logo/2016/0108/12202_1452248424_4592.png\";\n        }\n\n        if (iconPath.startsWith(\"http://\") || iconPath.startsWith(\"https://\")) {\n            return iconPath;\n        }\n        if (!iconPath.startsWith(\"/\")) {\n            iconPath = getPath() + \"/\" + iconPath;\n        }\n        if (iconPath.startsWith(\"/\")) {\n            iconPath = \"file://\" + iconPath;\n        }\n        return iconPath;\n    }\n\n    public void setIconPath(String iconPath) {\n        this.iconPath = iconPath;\n    }\n\n    public String getMainPath() {\n        if (!mainPath.startsWith(\"/\")) {\n            setMainPath(getPath() + \"/\" + mainPath);\n        }\n        return mainPath;\n    }\n\n    public void setMainPath(String mainPath) {\n        this.mainPath = mainPath;\n    }\n\n    public String getVersionName() {\n        return versionName;\n    }\n\n    public void setVersionName(String versionName) {\n        this.versionName = versionName;\n    }\n\n    public int getVersionCode() {\n        return versionCode;\n    }\n\n    public void setVersionCode(int versionCode) {\n        this.versionCode = versionCode;\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/utils/ColorStateListFactory.java",
    "content": "package androlua.utils;\n\nimport android.content.res.ColorStateList;\nimport android.graphics.drawable.ColorDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.RippleDrawable;\nimport android.graphics.drawable.ShapeDrawable;\nimport android.graphics.drawable.StateListDrawable;\nimport android.graphics.drawable.shapes.RoundRectShape;\nimport android.os.Build;\n\nimport java.util.Arrays;\n\n/**\n * Created by hanks on 2017/5/31. Copyright (C) 2017 Hanks\n */\n\npublic class ColorStateListFactory {\n\n    public static ColorStateList newInstance(int normalColor) {\n        return ColorStateList.valueOf(normalColor);\n    }\n\n    public static ColorStateList newInstance(int normalColor, int selectedColor) {\n        int[][] states = new int[][]{\n                {-android.R.attr.state_checked},\n                {android.R.attr.state_checked},\n                {android.R.attr.state_pressed},\n                {android.R.attr.state_enabled},\n                {android.R.attr.state_selected},\n        };\n        int[] colorList = new int[9];\n        colorList[0] = normalColor;\n        colorList[1] = selectedColor;\n        colorList[2] = selectedColor;\n        colorList[3] = selectedColor;\n        colorList[4] = selectedColor;\n        return new ColorStateList(states, colorList);\n    }\n\n\n    public static Drawable getRippleDrawable(\n            int normalColor, int pressedColor) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            return new RippleDrawable(ColorStateList.valueOf(pressedColor),\n                    null, getRippleMask(normalColor));\n        } else {\n            return getStateListDrawable(normalColor, pressedColor);\n        }\n    }\n\n    private static Drawable getRippleMask(int color) {\n        float[] outerRadii = new float[8];\n        // 3 is radius of final ripple,\n        // instead of 3 you can give required final radius\n        Arrays.fill(outerRadii, 3);\n\n        RoundRectShape r = new RoundRectShape(outerRadii, null, null);\n        ShapeDrawable shapeDrawable = new ShapeDrawable(r);\n        shapeDrawable.getPaint().setColor(color);\n        return shapeDrawable;\n    }\n\n    public static StateListDrawable getStateListDrawable(\n            int normalColor, int pressedColor) {\n        StateListDrawable states = new StateListDrawable();\n        states.addState(new int[]{android.R.attr.state_pressed},\n                new ColorDrawable(pressedColor));\n        states.addState(new int[]{android.R.attr.state_focused},\n                new ColorDrawable(pressedColor));\n        states.addState(new int[]{android.R.attr.state_activated},\n                new ColorDrawable(pressedColor));\n        states.addState(new int[]{},\n                new ColorDrawable(normalColor));\n        return states;\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/utils/DialogUtils.java",
    "content": "package androlua.utils;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.view.View;\nimport android.widget.EditText;\n\nimport com.luajava.LuaException;\nimport com.luajava.LuaObject;\nimport com.luajava.LuaTable;\n\nimport pub.hanks.luajandroid.R;\n\n/**\n * DialogUtils\n * Created by hanks on 2017/6/30.\n */\npublic class DialogUtils {\n    public static AlertDialog showWithInput(Context context, LuaTable config, final LuaObject callback) {\n        if (!(context instanceof Activity)) {\n            return null;\n        }\n        View view = View.inflate(context, R.layout.dialog_input, null);\n        final EditText et = (EditText) view.findViewById(R.id.et);\n        AlertDialog.Builder builder = new AlertDialog.Builder(context);\n        if (config.containsKey(\"title\")) {\n            builder.setTitle((String) config.get(\"title\"));\n        }\n        if (config.containsKey(\"msg\")) {\n            builder.setMessage((String) config.get(\"msg\"));\n        }\n        if (config.containsKey(\"cancelable\")) {\n            builder.setCancelable((Boolean) config.get(\"cancelable\"));\n        }\n        if (config.containsKey(\"content\")) {\n            et.setText((String) config.get(\"content\"));\n        }\n        if (config.containsKey(\"hit\")) {\n            et.setText((String) config.get(\"content\"));\n        }\n        if (config.containsKey(\"title\")) {\n            builder.setTitle((String) config.get(\"title\"));\n        }\n        if (config.containsKey(\"ok\")) {\n            builder.setPositiveButton((String) config.get(\"ok\"), new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    try {\n                        callback.call(et.getText().toString());\n                    } catch (LuaException e) {\n                        e.printStackTrace();\n                    }\n                }\n            });\n        } else {\n            builder.setPositiveButton(\"确定\", null);\n        }\n        if (config.containsKey(\"cancel\")) {\n            builder.setNegativeButton((String) config.get(\"cancel\"), null);\n        } else {\n            builder.setNegativeButton(\"取消\", null);\n        }\n        return  builder.create();\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/utils/LauncherUtil.java",
    "content": "package androlua.utils;\n\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ResolveInfo;\nimport android.text.TextUtils;\n\npublic class LauncherUtil {\n    public static final String READ_SETTINGS = \"READ_SETTINGS\";\n    public static final String WRITE_SETTINGS = \"WRITE_SETTINGS\";\n\n    private LauncherUtil() {\n    }\n\n    public static String getDefaultLauncher(Context context) {\n        try {\n            Intent intent = new Intent(\"android.intent.action.MAIN\");\n            intent.addCategory(\"android.intent.category.HOME\");\n            ResolveInfo resolveActivity = context.getPackageManager().resolveActivity(intent, 0);\n            if (resolveActivity.activityInfo.packageName.equals(\"android\")) {\n                return null;\n            }\n            return resolveActivity.activityInfo.packageName;\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    public static String getAuthorityFromPermission(Context context, String str) {\n        String str2 = null;\n        if (!(TextUtils.isEmpty(str) || context == null)) {\n            String defaultLauncher = getDefaultLauncher(context);\n            if (!TextUtils.isEmpty(defaultLauncher)) {\n                try {\n                    PackageInfo packageInfo = context.getPackageManager().getPackageInfo(defaultLauncher, PackageManager.GET_PROVIDERS);\n                    if (packageInfo != null) {\n                        ProviderInfo[] providerInfoArr = packageInfo.providers;\n                        if (providerInfoArr != null) {\n                            for (ProviderInfo providerInfo : providerInfoArr) {\n                                if ((!TextUtils.isEmpty(providerInfo.readPermission) && providerInfo.readPermission.contains(str)) || (!TextUtils.isEmpty(providerInfo.writePermission) && providerInfo.writePermission.contains(str))) {\n                                    str2 = providerInfo.authority;\n                                    break;\n                                }\n                            }\n                        }\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n        return str2;\n    }\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/utils/ShortcutUtils.java",
    "content": "package androlua.utils;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.ThreadPoolExecutor;\n\npublic class ShortcutUtils {\n\n    private static final String ACTION_INSTALL_SHORTCUT = \"com.android.launcher.action.INSTALL_SHORTCUT\";\n    private static final String ACTION_UNINSTALL_SHORTCUT = \"com.android.launcher.action.UNINSTALL_SHORTCUT\";\n    private static final String KEY_DUPLICATE = \"duplicate\";\n    private static final int POOL_SIZE = 3;\n    private static final String TAG = \"ShortcutUtil\";\n    private static ThreadPoolExecutor EXECUTOR = null;\n\n    static {\n        EXECUTOR = new ScheduledThreadPoolExecutor(POOL_SIZE);\n    }\n\n    private ShortcutUtils() {\n    }\n\n    public static void installShortcut(Context context, String str, int i, Intent intent) {\n        installShortcut(context, str, i, intent, null);\n    }\n\n    public static void installShortcut(final Context context, final String str, final int i, final Intent intent, final ActionListener actionListener) {\n        EXECUTOR.execute(new Runnable() {\n            @Override\n            public void run() {\n                addShortcut(context, str, i, intent);\n                if (actionListener != null) {\n                    actionListener.onSuccess();\n                }\n            }\n        });\n    }\n\n    public static void installShortcut(Context context, String str, Bitmap bm,  Intent intent) {\n        installShortcut(context, str, bm, intent, null);\n    }\n\n    public static void installShortcut(final Context context, final String str, final Bitmap bm, final Intent intent, final ActionListener actionListener) {\n        EXECUTOR.execute(new Runnable() {\n            @Override\n            public void run() {\n                addShortcut(context, str, bm,  intent);\n                if (actionListener != null) {\n                    actionListener.onSuccess();\n                }\n            }\n        });\n    }\n\n    public static void uninstallShortcut(Context context, String str, Intent intent) {\n        uninstallShortcut(context, str, intent, null);\n    }\n\n    public static void uninstallShortcut(final Context context, final String str, final Intent intent, final ActionListener actionListener) {\n        EXECUTOR.execute(new Runnable() {\n            @Override\n            public void run() {\n                removeShortcut(context, str, intent);\n                if (actionListener != null) {\n                    actionListener.onSuccess();\n                }\n            }\n        });\n    }\n\n    private static boolean addShortcut(Context context, String str, int i, Intent intent) {\n        intent.setAction(\"android.intent.action.MAIN\");\n        intent.addFlags(65536);\n        Intent intent2 = new Intent(ACTION_INSTALL_SHORTCUT);\n        intent2.putExtra(\"android.intent.extra.shortcut.INTENT\", intent);\n        intent2.putExtra(\"android.intent.extra.shortcut.NAME\", str);\n        intent2.putExtra(\"android.intent.extra.shortcut.ICON\", BitmapFactory.decodeResource(context.getResources(), i));\n        intent2.putExtra(\"android.intent.extra.shortcut.ICON_RESOURCE\", Intent.ShortcutIconResource.fromContext(context, i));\n        intent2.putExtra(KEY_DUPLICATE, false);\n        context.sendBroadcast(intent2);\n        return true;\n    }\n\n    private static boolean addShortcut(Context context, String str, Bitmap bm,  Intent intent) {\n        intent.setAction(\"android.intent.action.MAIN\");\n        intent.addFlags(65536);\n        Intent intent2 = new Intent(ACTION_INSTALL_SHORTCUT);\n        intent2.putExtra(\"android.intent.extra.shortcut.INTENT\", intent);\n        intent2.putExtra(\"android.intent.extra.shortcut.NAME\", str);\n        intent2.putExtra(\"android.intent.extra.shortcut.ICON\", bm);\n        intent2.putExtra(KEY_DUPLICATE, false);\n        context.sendBroadcast(intent2);\n        return true;\n    }\n\n    private static void removeShortcut(Context context, String str, Intent intent) {\n        intent.setAction(\"android.intent.action.MAIN\");\n        Intent intent2 = new Intent(ACTION_UNINSTALL_SHORTCUT);\n        intent2.putExtra(\"android.intent.extra.shortcut.INTENT\", intent);\n        intent2.putExtra(\"android.intent.extra.shortcut.NAME\", str);\n        context.sendBroadcast(intent2);\n    }\n\n    public static boolean hasShortcut(Context context, String str) {\n        boolean z = false;\n        Exception e;\n        Throwable th;\n        Cursor cursor = null;\n        if (TextUtils.isEmpty(str)) {\n            return false;\n        }\n        String authorityFromPermission = LauncherUtil.getAuthorityFromPermission(context, LauncherUtil.READ_SETTINGS);\n        if (TextUtils.isEmpty(authorityFromPermission)) {\n            return false;\n        }\n        Cursor query;\n        try {\n            query = context.getContentResolver().query(Uri.parse(\"content://\" + authorityFromPermission + \"/favorites?notify=true\"), null, \"title=?\", new String[]{str}, null);\n            if (query != null) {\n                try {\n                    if (query.getCount() > 0) {\n                        z = true;\n                        if (query != null) {\n                            query.close();\n                        }\n                        return z;\n                    }\n                } catch (Exception e2) {\n                    e = e2;\n                    try {\n                        e.printStackTrace();\n                        if (query == null) {\n                            query.close();\n                            z = false;\n                        } else {\n                            z = false;\n                        }\n                        return z;\n                    } catch (Throwable th2) {\n                        th = th2;\n                        cursor = query;\n                        if (cursor != null) {\n                            cursor.close();\n                        }\n                        throw th;\n                    }\n                }\n            }\n            z = false;\n            if (query != null) {\n                query.close();\n            }\n        } catch (Exception e3) {\n            e = e3;\n            query = null;\n            e.printStackTrace();\n            if (query == null) {\n                z = false;\n            } else {\n                query.close();\n                z = false;\n            }\n            return z;\n        } catch (Throwable th3) {\n            th = th3;\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n        return z;\n    }\n\n    public interface ActionListener {\n        void onFailure(int i);\n\n        void onSuccess();\n    }\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/glide/LuaGlideModule.java",
    "content": "package androlua.widget.glide;\n\nimport android.content.Context;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.GlideBuilder;\nimport com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool;\nimport com.bumptech.glide.load.engine.cache.LruResourceCache;\nimport com.bumptech.glide.module.GlideModule;\n\n/**\n * custom glide\n * Created by hanks on 2017/6/1.\n */\n\npublic class LuaGlideModule implements GlideModule {\n    @Override\n    public void applyOptions(Context context, GlideBuilder builder) {\n        int memoryCacheSize = 1024 * 1024 * 10;//设置图片内存缓存占用八分之一\n        //设置内存缓存大小\n        builder.setMemoryCache(new LruResourceCache(memoryCacheSize));\n        //设置BitmapPool缓存内存大小\n        builder.setBitmapPool(new LruBitmapPool(memoryCacheSize));\n    }\n\n    @Override\n    public void registerComponents(Context context, Glide glide) {\n\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/htmltext/URLImageParser.java",
    "content": "package androlua.widget.htmltext;\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.ColorFilter;\nimport android.graphics.Paint;\nimport android.graphics.drawable.Drawable;\nimport android.text.Html;\nimport android.util.DisplayMetrics;\nimport android.util.Log;\nimport android.view.WindowManager;\nimport android.widget.TextView;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\nimport com.bumptech.glide.load.resource.drawable.GlideDrawable;\nimport com.bumptech.glide.load.resource.gif.GifDrawable;\nimport com.bumptech.glide.request.RequestListener;\nimport com.bumptech.glide.request.animation.GlideAnimation;\nimport com.bumptech.glide.request.target.Target;\nimport com.bumptech.glide.request.target.ViewTarget;\n\n\npublic class URLImageParser implements Html.ImageGetter {\n    private TextView container;\n\n    public URLImageParser(TextView v) {\n        this.container = v;\n    }\n\n    @Override\n    public Drawable getDrawable(String url) {\n        final UrlDrawable urlDrawable = new UrlDrawable();\n        final String source = url;\n\n        debug(\"Url is \" + url);\n        DisplayMetrics metrics = new DisplayMetrics();\n        ((WindowManager) container.getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metrics);\n        final float dpi = (int) metrics.density;\n\n        Glide.with(container.getContext()).load(source).diskCacheStrategy(DiskCacheStrategy.ALL).\n                listener(new RequestListener<String, GlideDrawable>() {\n                    @Override\n                    public boolean onException(Exception e, String s, Target<GlideDrawable> glideDrawableTarget, boolean b) {\n                        debug(\"Error in Glide listener\");\n                        if (e != null) {\n                            e.printStackTrace();\n                        }\n                        return false;\n                    }\n\n                    @Override\n                    public boolean onResourceReady(GlideDrawable glideDrawable, String s, Target<GlideDrawable> glideDrawableTarget, boolean b, boolean b2) {\n                        return false;\n                    }\n                }).\n                into(new ViewTarget<TextView, GlideDrawable>(container) {\n                    @Override\n                    public void onResourceReady(GlideDrawable d, GlideAnimation<? super GlideDrawable> glideAnimation) {\n                        int width = (int) (d.getIntrinsicWidth() * dpi);\n                        int height = (int) (d.getIntrinsicHeight() * dpi);\n                        d.setBounds(0, 0, width, height);\n                        d.setVisible(true, true);\n\n                        d.setCallback(new Drawable.Callback() {\n                            @Override\n                            public void invalidateDrawable(Drawable who) {\n\n                            }\n\n                            @Override\n                            public void scheduleDrawable(Drawable who, Runnable what, long when) {\n\n                            }\n\n                            @Override\n                            public void unscheduleDrawable(Drawable who, Runnable what) {\n\n                            }\n                        });\n\n                        urlDrawable.setBounds(0, 0, width, height);\n                        urlDrawable.drawable = d;\n                        debug(\"Lisnt1er ended \" + width + \", \" + height + \", source: \" + source + \", animated? \" + d.isAnimated() + \", \" + d.getClass().getSimpleName());\n\n                        if (d instanceof GifDrawable) {\n                            debug(\"Gif drawable ! animated? \" + d.isAnimated() + \", \" + (d.getCallback() == null));\n                            GifDrawable a = (GifDrawable) d;\n                            d.setLoopCount(GlideDrawable.LOOP_FOREVER);\n                            d.start();\n                        }\n                    }\n\n                });\n        return urlDrawable;\n    }\n\n    private void debug(String msg) {\n        Log.d(\"AAA\", msg);\n    }\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/htmltext/UrlDrawable.java",
    "content": "package androlua.widget.htmltext;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.ColorFilter;\nimport android.graphics.Paint;\nimport android.graphics.PixelFormat;\nimport android.graphics.drawable.Drawable;\n\nimport com.bumptech.glide.load.resource.drawable.GlideDrawable;\n\n\npublic class UrlDrawable extends Drawable {\n    public GlideDrawable drawable;\n\n    public UrlDrawable() {\n        super();\n    }\n\n    @Override\n    public void setAlpha(int alpha) {\n        if (drawable != null) {\n            drawable.setAlpha(alpha);\n        }\n    }\n\n    @Override\n    public void setColorFilter(ColorFilter cf) {\n        if (drawable != null) {\n            drawable.setColorFilter(cf);\n        }\n    }\n\n    @Override\n    public int getOpacity() {\n        if (drawable != null) {\n            return drawable.getOpacity();\n        }\n        return PixelFormat.UNKNOWN;\n    }\n\n    @Override\n    public void draw(Canvas canvas) {\n// override the draw to facilitate refresh function later\n        if (drawable != null) {\n            Paint p = new Paint();\n            p.setColor(Color.GREEN);\n            canvas.drawRect(drawable.getBounds(), p);\n            drawable.draw(canvas);\n\n            if (!drawable.isRunning()) {\n                drawable.start();\n            }\n        }\n    }\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/marqueetext/MarqueeTextView.java",
    "content": "package androlua.widget.marqueetext;\n\nimport android.content.Context;\nimport android.support.annotation.Nullable;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.widget.TextView;\n\n/**\n * 跑马灯\n * Created by hanks on 2017/6/21.\n */\n\npublic class MarqueeTextView extends android.support.v7.widget.AppCompatTextView {\n    public MarqueeTextView(Context context) {\n        this(context,null);\n    }\n\n    public MarqueeTextView(Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public MarqueeTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        setSingleLine(true);\n        setMaxLines(1);\n        setEllipsize(TextUtils.TruncateAt.MARQUEE);\n    }\n\n    @Override\n    public boolean isFocused() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/ninegride/LuaNineGridView.java",
    "content": "package androlua.widget.ninegride;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\n\nimport com.luajava.LuaTable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by hanks on 2017/5/31. Copyright (C) 2017 Hanks\n */\n\npublic class LuaNineGridView extends NineGridImageView {\n\n    public LuaNineGridView(Context context) {\n        super(context);\n    }\n\n    public LuaNineGridView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public void setImagesData(LuaTable lists) {\n        List<String> data = new ArrayList<>();\n        int size = lists.size();\n        for (int i = 1; i <= size; i++) {\n            data.add((String) lists.get(i));\n        }\n        setImagesData(data);\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/ninegride/LuaNineGridViewAdapter.java",
    "content": "package androlua.widget.ninegride;\n\nimport android.content.Context;\nimport android.widget.ImageView;\n\nimport java.util.List;\n\n/**\n * Created by hanks on 2017/5/31. Copyright (C) 2017 Hanks\n */\n\npublic class LuaNineGridViewAdapter extends NineGridImageViewAdapter {\n    AdapterCreator adapterCreator;\n\n    public LuaNineGridViewAdapter(AdapterCreator adapterCreator) {\n        this.adapterCreator = adapterCreator;\n    }\n\n    @Override\n    protected void onDisplayImage(Context context, ImageView imageView, String url) {\n        adapterCreator.onDisplayImage(context, imageView, url);\n    }\n\n    @Override\n    protected void onItemImageClick(Context context, ImageView imageView, int index, List<String> list) {\n        super.onItemImageClick(context, imageView, index, list);\n        adapterCreator.onItemImageClick(context, imageView, index, list);\n    }\n\n    public interface AdapterCreator {\n        void onDisplayImage(Context context, ImageView imageView, String url);\n\n        void onItemImageClick(Context context, ImageView imageView, int index, List<String> list);\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/ninegride/NineGridImageView.java",
    "content": "package androlua.widget.ninegride;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport androlua.LuaImageLoader;\n\n/**\n * Created by Jaeger on 16/2/24.\n * <p>\n * Email: chjie.jaeger@gamil.com\n * GitHub: https://github.com/laobie\n */\npublic class NineGridImageView<T> extends ViewGroup {\n\n    public final static int STYLE_GRID = 0;     // 宫格布局\n    public final static int STYLE_FILL = 1;     // 全填充布局\n\n    private int mRowCount;       // 行数\n    private int mColumnCount;    // 列数\n\n    private int mMaxSize;        // 最大图片数\n    private int mShowStyle;     // 显示风格\n    private int mGap;           // 宫格间距\n    private int mSingleImgWidth;\n    private int mSingleImgHeight; // 单张图片时的尺寸\n    private int mGridSize;   // 宫格大小,即图片大小\n\n    private List<ImageView> mImageViewList = new ArrayList<>();\n    private List<String> mImgDataList = new ArrayList<>();\n    private NineGridImageViewAdapter mAdapter;\n    private int totalWidth;\n\n    public NineGridImageView(Context context) {\n        this(context, null);\n    }\n\n    public NineGridImageView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        this.mGap = 0;\n        this.mSingleImgHeight = dp2px(180);\n        this.mSingleImgWidth = dp2px(180);\n        this.mShowStyle = STYLE_GRID;\n        this.mMaxSize = 9;\n    }\n\n    /**\n     * 设置 宫格参数\n     *\n     * @param imagesSize 图片数量\n     * @param showStyle  显示风格\n     * @return 宫格参数 gridParam[0] 宫格行数 gridParam[1] 宫格列数\n     */\n    protected static int[] calculateGridParam(int imagesSize, int showStyle) {\n        int[] gridParam = new int[2];\n        switch (showStyle) {\n            case STYLE_FILL:\n                if (imagesSize < 3) {\n                    gridParam[0] = 1;\n                    gridParam[1] = imagesSize;\n                } else if (imagesSize <= 4) {\n                    gridParam[0] = 2;\n                    gridParam[1] = 2;\n                } else {\n                    gridParam[0] = imagesSize / 3 + (imagesSize % 3 == 0 ? 0 : 1);\n                    gridParam[1] = 3;\n                }\n                break;\n            default:\n            case STYLE_GRID:\n                gridParam[0] = imagesSize / 3 + (imagesSize % 3 == 0 ? 0 : 1);\n                gridParam[1] = 3;\n        }\n        return gridParam;\n    }\n\n    public void setSingleImgSize(int width, int height) {\n        int targetH = dp2px(180);\n        int targetW = getScreenWidth() - dp2px(32);\n        if (height > 2000) {\n            height = 2000;\n        }\n        if (width > 3000) {\n            width = 3000;\n        }\n        float scale = 1f;\n        float scaleY = targetH * 1f / height;\n        float scaleX = targetW * 1f / width;\n        if (height < targetH) {\n            if (width * scaleY > targetW) {\n                scale = scaleX;\n            } else {\n                scale = scaleY;\n            }\n        } else {\n            scale = Math.min(scaleX, scaleY);\n        }\n        this.mSingleImgWidth = (int) (width * scale);\n        this.mSingleImgHeight = (int) (height * scale);\n\n    }\n\n    public NineGridImageViewAdapter getAdapter() {\n        return mAdapter;\n    }\n\n    /**\n     * 设置适配器\n     *\n     * @param adapter 适配器\n     */\n    public void setAdapter(NineGridImageViewAdapter adapter) {\n        mAdapter = adapter;\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n        int width = MeasureSpec.getSize(widthMeasureSpec);\n        int height = MeasureSpec.getSize(heightMeasureSpec);\n        totalWidth = width - getPaddingLeft() - getPaddingRight();\n        if (mImgDataList == null || mImgDataList.isEmpty()) {\n            setMeasuredDimension(width, height);\n            return;\n        }\n        switch (mImgDataList.size()) {\n            case 1:\n                mColumnCount = 1;\n                mRowCount = 1;\n                mGridSize = height = mSingleImgHeight;\n                break;\n            case 2:\n            case 4:\n                mGridSize = (int) ((totalWidth - mGap) / 2f);\n                mRowCount = mImgDataList.size() / 2;\n                mColumnCount = 2;\n                height = mGridSize * mRowCount + mGap * (mRowCount - 1);\n                break;\n            default:\n                mColumnCount = 3;\n                mRowCount = mImgDataList.size() % 3 == 0 ? mImgDataList.size() / 3 : mImgDataList.size() / 3 + 1;\n                mGridSize = (int) ((totalWidth - 2 * mGap) / 3f);\n                height = mGridSize * mRowCount + (mGap * mRowCount - 1);\n                break;\n        }\n        height = height + getPaddingTop() + getPaddingBottom();\n        setMeasuredDimension(width, height);\n    }\n\n    private int dp2px(float dp) {\n        float density = getContext().getResources().getDisplayMetrics().density;\n        return (int) (0.5F + dp * density);\n    }\n\n    private int getScreenWidth() {\n        return getContext().getResources().getDisplayMetrics().widthPixels;\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int l, int t, int r, int b) {\n        int childCount = getChildCount();\n        if (childCount == 0) {\n            return;\n        }\n        if (childCount == 1) {\n            View child = getChildAt(0);\n            child.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + mSingleImgWidth, getPaddingTop() + mSingleImgHeight);\n            return;\n        }\n\n        for (int i = 0; i < childCount; i++) {\n            View child = getChildAt(i);\n            int rowNum = i / mColumnCount;\n            int columnNum = i % mColumnCount;\n            int left = (mGridSize + mGap) * columnNum + getPaddingLeft();\n            int top = (mGridSize + mGap) * rowNum + getPaddingTop();\n            int right = left + mGridSize;\n            int bottom = top + mGridSize;\n            child.layout(left, top, right, bottom);\n        }\n    }\n\n\n    /**\n     * 设置图片数据\n     *\n     * @param lists 图片数据集合\n     */\n    public void setImagesData(List<String> lists) {\n        if (lists == null || lists.isEmpty()) {\n            this.setVisibility(GONE);\n            return;\n        } else {\n            this.setVisibility(VISIBLE);\n        }\n        removeAllViews();\n        int newShowCount = getNeedShowCount(lists.size());\n        int[] gridParam = calculateGridParam(newShowCount, mShowStyle);\n        mRowCount = gridParam[0];\n        mColumnCount = gridParam[1];\n        mImgDataList.clear();\n        mImgDataList.addAll(lists);\n        for (int i = 0; i < newShowCount; i++) {\n            ImageView iv = getImageView();\n            if (iv == null) {\n                continue;\n            }\n            int w,h;\n            if (newShowCount == 1) {\n                iv.setScaleType(ImageView.ScaleType.FIT_XY);\n                w = mSingleImgWidth;\n                h = mSingleImgHeight;\n            } else {\n                w = h = mGridSize;\n                iv.setScaleType(ImageView.ScaleType.CENTER_CROP);\n            }\n\n            addView(iv, new ViewGroup.LayoutParams(w,h));\n            LuaImageLoader.load(iv, mImgDataList.get(i));\n            final int finalI = i;\n            iv.setOnClickListener(new OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    mAdapter.onItemImageClick(getContext(), (ImageView) v, finalI, mImgDataList);\n                }\n            });\n            mAdapter.onDisplayImage(getContext(), iv, mImgDataList.get(i));\n        }\n        requestLayout();\n    }\n\n    private int getNeedShowCount(int size) {\n        if (mMaxSize > 0 && size > mMaxSize) {\n            return mMaxSize;\n        } else {\n            return size;\n        }\n    }\n\n    /**\n     * 获得 ImageView\n     * 保证了 ImageView 的重用\n     */\n    private ImageView getImageView() {\n        if (mAdapter != null) {\n            ImageView imageView = mAdapter.generateImageView(getContext());\n\n            return imageView;\n        } else {\n            Log.e(\"NineGirdImageView\", \"Your must set a NineGridImageViewAdapter for NineGirdImageView\");\n            return null;\n        }\n    }\n\n    /**\n     * 设置宫格间距\n     *\n     * @param gap 宫格间距 px\n     */\n    public void setGap(int gap) {\n        mGap = gap;\n    }\n\n    /**\n     * 设置显示风格\n     *\n     * @param showStyle 显示风格\n     */\n    public void setShowStyle(int showStyle) {\n        mShowStyle = showStyle;\n    }\n\n\n    /**\n     * 设置最大图片数\n     *\n     * @param maxSize 最大图片数\n     */\n    public void setMaxSize(int maxSize) {\n        mMaxSize = maxSize;\n    }\n\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/ninegride/NineGridImageViewAdapter.java",
    "content": "package androlua.widget.ninegride;\n\nimport android.content.Context;\nimport android.widget.ImageView;\n\nimport java.util.List;\n\n/**\n * Created by Jaeger on 16/2/24.\n * <p>\n * Email: chjie.jaeger@gmail.com\n * GitHub: https://github.com/laobie\n */\npublic abstract class NineGridImageViewAdapter {\n    protected abstract void onDisplayImage(Context context, ImageView imageView, String t);\n\n    protected void onItemImageClick(Context context, ImageView imageView, int index, List<String> list) {\n    }\n\n    protected ImageView generateImageView(Context context) {\n        ImageView imageView = new ImageView(context);\n        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);\n        return imageView;\n    }\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/picture/ElasticDragDismissFrameLayout.java",
    "content": "/*\n * Copyright 2015 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage androlua.widget.picture;\n\nimport android.animation.ValueAnimator;\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.graphics.RectF;\nimport android.support.v4.view.ViewCompat;\nimport android.util.AttributeSet;\nimport android.util.DisplayMetrics;\nimport android.util.TypedValue;\nimport android.view.View;\nimport android.view.WindowManager;\nimport android.view.animation.AccelerateInterpolator;\nimport android.view.animation.Interpolator;\nimport android.widget.FrameLayout;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ElasticDragDismissFrameLayout extends FrameLayout {\n\n    public static final float DRAG_ELASTICITY_NORMAL = .5f;\n    public static final float DRAG_ELASTICITY_LARGE = .9f;\n    public static final float DRAG_ELASTICITY_XLARGE = 1.25f;\n    public static final float DRAG_ELASTICITY_XXLARGE = 2f;\n\n    // configurable attribs\n    private float dragDismissDistance = Float.MAX_VALUE;\n    private float alplaDistance = Float.MAX_VALUE;\n    private float dragDismissFraction = -1f;\n    private float dragDismissScale = 0.7f; // 0..1\n    private boolean shouldScale = false;\n    private float dragElasticity = DRAG_ELASTICITY_NORMAL;\n\n    // state\n    private float totalDrag;\n    private boolean draggingDown = false;\n    private boolean draggingUp = false;\n\n    private boolean enabled = true;\n\n    private static Interpolator fastOutSlowInInterpolator;\n\n    private List<ElasticDragDismissCallback> callbacks;\n\n    private RectF draggingBackground;\n    private int bgAlpha;\n\n    public ElasticDragDismissFrameLayout(Context context) {\n        this(context, null, 0);\n    }\n\n    public ElasticDragDismissFrameLayout(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public ElasticDragDismissFrameLayout(Context context, AttributeSet attrs,\n                                         int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init();\n    }\n\n    private void init() {\n        DisplayMetrics metrics = new DisplayMetrics();\n        WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);\n        windowManager.getDefaultDisplay().getMetrics(metrics);\n        dragDismissDistance = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 180, metrics);\n        alplaDistance = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 600, metrics);\n\n        shouldScale = dragDismissScale != 1f;\n\n        setBackgroundColor(0xff000000);\n    }\n\n    public static abstract class ElasticDragDismissCallback {\n\n        /**\n         * Called for each drag event.\n         *\n         * @param elasticOffset       Indicating the drag offset with elasticity applied i.e. may\n         *                            exceed 1.\n         * @param elasticOffsetPixels The elastically scaled drag distance in pixels.\n         * @param rawOffset           Value from [0, 1] indicating the raw drag offset i.e.\n         *                            without elasticity applied. A value of 1 indicates that the\n         *                            dismiss distance has been reached.\n         * @param rawOffsetPixels     The raw distance the user has dragged\n         */\n        public void onDrag(float elasticOffset, float elasticOffsetPixels,\n                           float rawOffset, float rawOffsetPixels) {\n        }\n\n        /**\n         * Called when dragging is released and has exceeded the threshold dismiss distance.\n         */\n        public void onDragDismissed() {\n        }\n\n    }\n\n    @Override\n    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {\n        return enabled && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;\n    }\n\n    @Override\n    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {\n        if (!enabled) {\n            return;\n        }\n\n        if (draggingDown && dy > 0 || draggingUp && dy < 0) {\n            dragScale(dy);\n            consumed[1] = dy;\n        }\n    }\n\n    @Override\n    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,\n                               int dxUnconsumed, int dyUnconsumed) {\n        if (enabled) {\n            dragScale(dyUnconsumed);\n        }\n    }\n\n    @Override\n    public void onStopNestedScroll(View child) {\n        if (enabled) {\n            if (Math.abs(totalDrag) >= dragDismissDistance) {\n                dispatchDismissCallback();\n            } else { // settle back to natural position\n                if (fastOutSlowInInterpolator == null) {\n                    fastOutSlowInInterpolator = new AccelerateInterpolator();\n                }\n                getChildAt(0).animate()\n                        .translationY(0f)\n                        .scaleX(1f)\n                        .scaleY(1f)\n                        .setDuration(200L)\n                        .setInterpolator(fastOutSlowInInterpolator)\n                        .start();\n                ValueAnimator animator = ValueAnimator.ofInt(bgAlpha, 255);\n                animator.setDuration(200);\n                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {\n                    @Override\n                    public void onAnimationUpdate(ValueAnimator animation) {\n                        int v = (int) animation.getAnimatedValue();\n                        setBackgroundColor(Color.argb(v, 0, 0, 0));\n                    }\n                });\n                animator.start();\n\n                totalDrag = 0;\n                draggingDown = draggingUp = false;\n                dispatchDragCallback(0f, 0f, 0f, 0f);\n            }\n        }\n    }\n\n    @Override\n    protected void onSizeChanged(int w, int h, int oldw, int oldh) {\n        super.onSizeChanged(w, h, oldw, oldh);\n        if (dragDismissFraction > 0f) {\n            dragDismissDistance = h * dragDismissFraction;\n        }\n    }\n\n    public void addListener(ElasticDragDismissCallback listener) {\n        if (callbacks == null) {\n            callbacks = new ArrayList<>();\n        }\n        callbacks.add(listener);\n    }\n\n    public void setEnabled(boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public boolean isEnabled() {\n        return enabled;\n    }\n\n    public void removeListener(ElasticDragDismissCallback listener) {\n        if (callbacks != null && callbacks.size() > 0) {\n            callbacks.remove(listener);\n        }\n    }\n\n    private void dragScale(int scroll) {\n        if (scroll == 0) return;\n\n        totalDrag += scroll;\n        View child = getChildAt(0);\n\n        // track the direction & set the pivot point for scaling\n        // don't double track i.e. if play dragging down and then reverse, keep tracking as\n        // dragging down until they reach the 'natural' position\n        if (scroll < 0 && !draggingUp && !draggingDown) {\n            draggingDown = true;\n            if (shouldScale) child.setPivotY(getHeight());\n        } else if (scroll > 0 && !draggingDown && !draggingUp) {\n            draggingUp = true;\n            if (shouldScale) child.setPivotY(0f);\n        }\n        // how far have we dragged relative to the distance to perform a dismiss\n        // (0–1 where 1 = dismiss distance). Decreasing logarithmically as we approach the limit\n        float dragFraction = (float) Math.log10(1 + (Math.abs(totalDrag) / dragDismissDistance));\n\n        // calculate the desired translation given the drag fraction\n        float dragTo = dragFraction * dragDismissDistance * dragElasticity;\n\n        if (draggingUp) {\n            // as we use the absolute magnitude when calculating the drag fraction, need to\n            // re-apply the drag direction\n            dragTo *= -1;\n        }\n        child.setTranslationY(dragTo);\n\n        if (draggingBackground == null) {\n            draggingBackground = new RectF();\n            draggingBackground.left = 0;\n            draggingBackground.right = getWidth();\n            draggingBackground.top = 0;\n            draggingBackground.bottom = getHeight();\n        }\n\n\n        float dx = Math.abs(totalDrag);\n        dx = dx > alplaDistance ? alplaDistance : dx;\n        bgAlpha = (int) (255 * (1f - (dx / alplaDistance)));\n        bgAlpha = bgAlpha > 255 ? 255 : bgAlpha;\n        bgAlpha = bgAlpha < 0 ? 0 : bgAlpha;\n        setBackgroundColor(Color.argb(bgAlpha, 0, 0, 0));\n\n\n        if (shouldScale) {\n            final float scale = 1 - ((1 - dragDismissScale) * dragFraction);\n            child.setScaleX(scale);\n            child.setScaleY(scale);\n        }\n\n        // if we've reversed direction and gone past the settle point then clear the flags to\n        // allow the list to get the scroll events & reset any transforms\n        if ((draggingDown && totalDrag >= 0)\n                || (draggingUp && totalDrag <= 0)) {\n            totalDrag = dragTo = dragFraction = 0;\n            draggingDown = draggingUp = false;\n            child.setTranslationY(0f);\n            child.setScaleX(1f);\n            child.setScaleY(1f);\n        }\n        invalidate();\n\n        dispatchDragCallback(dragFraction, dragTo,\n                Math.min(1f, Math.abs(totalDrag) / dragDismissDistance), totalDrag);\n    }\n\n    private void dispatchDragCallback(float elasticOffset, float elasticOffsetPixels,\n                                      float rawOffset, float rawOffsetPixels) {\n        if (callbacks != null && !callbacks.isEmpty()) {\n            for (ElasticDragDismissCallback callback : callbacks) {\n                callback.onDrag(elasticOffset, elasticOffsetPixels,\n                        rawOffset, rawOffsetPixels);\n            }\n        }\n    }\n\n    private void dispatchDismissCallback() {\n        if (callbacks != null && !callbacks.isEmpty()) {\n            for (ElasticDragDismissCallback callback : callbacks) {\n                callback.onDragDismissed();\n            }\n        }\n    }\n\n    public boolean isDragging() {\n        return draggingDown || draggingUp;\n    }\n\n\n    public void setDragElasticity(float elasticity) {\n        this.dragElasticity = elasticity;\n    }\n\n    public void halfDistanceRequired() {\n        this.dragDismissDistance = dragDismissDistance / 2;\n    }\n\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/picture/PicturePreviewActivity.java",
    "content": "package androlua.widget.picture;\n\nimport android.Manifest;\nimport android.app.DownloadManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Color;\nimport android.graphics.PointF;\nimport android.graphics.drawable.Drawable;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Environment;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.ActivityCompat;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.content.ContextCompat;\nimport android.support.v4.view.ViewPager;\nimport android.support.v7.app.AppCompatActivity;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.Window;\nimport android.widget.ImageView;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\nimport com.bumptech.glide.load.model.GlideUrl;\nimport com.bumptech.glide.load.model.LazyHeaders;\nimport com.bumptech.glide.request.animation.GlideAnimation;\nimport com.bumptech.glide.request.target.SimpleTarget;\nimport com.davemorrissey.labs.subscaleview.ImageSource;\nimport com.davemorrissey.labs.subscaleview.ImageViewState;\nimport com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.util.ArrayList;\n\nimport androlua.LuaHttp;\nimport androlua.adapter.LuaFragmentPageAdapter;\nimport androlua.base.BaseFragment;\nimport androlua.common.LuaFileUtils;\nimport androlua.common.LuaStringUtils;\nimport androlua.common.LuaToast;\nimport pub.hanks.luajandroid.R;\n\n/**\n * Created by hanks on 2017/6/2. Copyright (C) 2017 Hanks\n */\n\npublic class PicturePreviewActivity extends AppCompatActivity {\n\n    private LuaFragmentPageAdapter adapter;\n    private ArrayList<String> uris = new ArrayList<>();\n    private ArrayList<Fragment> fragments = new ArrayList<>();\n    private int currentIndex;\n    private ViewPager viewPager;\n    private TextView tv_count;\n    private ArrayList<String> headerList = new ArrayList<>();\n    private boolean isVisible;\n    private ImageView iv_share, iv_download;\n    private Context context;\n\n    public static void start(Context context, String json) {\n        Intent starter = new Intent(context, PicturePreviewActivity.class);\n        starter.putExtra(\"json\", json);\n        context.startActivity(starter);\n    }\n\n\n    public void setStatusBarColor(int color) {\n        if (Build.VERSION.SDK_INT >= 21) {\n            View decorView = getWindow().getDecorView();\n            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN\n                    | View.SYSTEM_UI_FLAG_IMMERSIVE\n                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;\n            decorView.setSystemUiVisibility(option);\n            getWindow().setStatusBarColor(color);\n        }\n    }\n\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        overridePendingTransition( android.R.anim.fade_in, 0);//结束的动画\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_picture);\n        context = this;\n\n        setStatusBarColor(Color.TRANSPARENT);\n        getWindow().setBackgroundDrawableResource(android.R.color.transparent);\n        getWindow().getDecorView().setBackgroundColor(Color.TRANSPARENT);\n\n        ElasticDragDismissFrameLayout dragDismissLayout = (ElasticDragDismissFrameLayout) findViewById(R.id.dragdismiss_drag_dismiss_layout);\n        dragDismissLayout.addListener(new ElasticDragDismissFrameLayout.ElasticDragDismissCallback() {\n            @Override\n            public void onDragDismissed() {\n                super.onDragDismissed();\n                PicturePreviewActivity.this.finish();\n            }\n        });\n\n        dragDismissLayout.setDragElasticity(ElasticDragDismissFrameLayout.DRAG_ELASTICITY_XXLARGE);\n        dragDismissLayout.halfDistanceRequired();\n\n        tv_count = (TextView) findViewById(R.id.tv_count);\n        iv_download = (ImageView) findViewById(R.id.iv_download);\n        iv_share = (ImageView) findViewById(R.id.iv_share);\n        viewPager = (ViewPager) findViewById(R.id.viewpager);\n        adapter = new LuaFragmentPageAdapter(getSupportFragmentManager(), new LuaFragmentPageAdapter.AdapterCreator() {\n            @Override\n            public long getCount() {\n                return fragments.size();\n            }\n\n            @Override\n            public Fragment getItem(int position) {\n                return fragments.get(position);\n            }\n\n            @Override\n            public String getPageTitle(int position) {\n                return (position + 1) + \"/\" + fragments.size();\n            }\n        });\n        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {\n            @Override\n            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {\n\n            }\n\n            @Override\n            public void onPageSelected(int position) {\n                tv_count.setText(adapter.getPageTitle(position));\n            }\n\n            @Override\n            public void onPageScrollStateChanged(int state) {\n\n            }\n        });\n        viewPager.setAdapter(adapter);\n        getData();\n        iv_download.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                try {\n                    int hasWriteContactsPermission = ContextCompat.checkSelfPermission(PicturePreviewActivity.this,\n                            Manifest.permission.WRITE_EXTERNAL_STORAGE);\n                    if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {\n                        requestPermission();\n                    } else {\n                        int currentItem = viewPager.getCurrentItem();\n                        downloadPicture(context, uris.get(currentItem), headerList);\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        });\n        iv_share.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                try {\n                    Intent sendIntent = new Intent(Intent.ACTION_SEND);\n                    int i = viewPager.getCurrentItem();\n                    sendIntent.putExtra(Intent.EXTRA_TEXT, uris.get(i) +  \"\\n来自【氢应用】https://www.coolapk.com/apk/pub.hydrogen.android \" );\n                    sendIntent.setType(\"text/plain\");\n                    if (sendIntent.resolveActivity(getPackageManager()) != null) {\n                        startActivity(sendIntent);\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        });\n    }\n\n    private void getData() {\n        // { \"uris\":[], \"currentIndex\":0, \"headers\":[\"UA:android\",\"\"] }\n        String str = getIntent().getStringExtra(\"json\");\n\n        if (TextUtils.isEmpty(str) && Intent.ACTION_VIEW.equals(getIntent().getAction())) {\n            Uri uri = getIntent().getData();\n            str = uri.getQueryParameter(\"data\");\n        }\n\n        if (TextUtils.isEmpty(str)) {\n            Toast.makeText(this, \"数据出错\", Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        try {\n            JSONObject json = new JSONObject(str);\n            if (json.has(\"headers\")) {\n                JSONArray headers = json.getJSONArray(\"headers\");\n                for (int i = 0; i < headers.length(); i++) {\n                    headerList.add(headers.getString(i));\n                }\n            }\n            if (json.has(\"uris\")) {\n                JSONArray list = json.getJSONArray(\"uris\");\n                for (int i = 0; i < list.length(); i++) {\n                    uris.add(list.getString(i));\n                }\n            }\n            if (json.has(\"currentIndex\")) {\n                currentIndex = json.getInt(\"currentIndex\");\n            }\n\n            tv_count.setText(String.format(\"%s/%s\", 1, uris.size()));\n            for (final String uri : uris) {\n                PicturePreviewFragment fragment = PicturePreviewFragment.newInstance(uri, headerList);\n                fragments.add(fragment);\n            }\n            adapter.notifyDataSetChanged();\n            viewPager.setCurrentItem(currentIndex, false);\n\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n    }\n\n\n    private void downloadPicture(Context context, final String uri, final ArrayList<String> headers) {\n        try {\n            DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);  //得到系统的下载管理\n            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(uri));  //得到连接请求对象\n            //request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);\n            if (headers != null) {\n                for (String header : headers) {\n                    int i = header.indexOf(\":\");\n                    if (i <= 0) {\n                        continue;\n                    }\n                    String key = header.substring(0, i);\n                    String v = header.substring(i + 1);\n                    request.addRequestHeader(key, v);\n                }\n            }\n            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);\n            request.setDescription(\"下载中...\");\n            request.setTitle(\"下载\");\n            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_PICTURES, System.currentTimeMillis() + \".jpg\");\n            manager.enqueue(request);\n            LuaToast.show(\"正在保存...\");\n        } catch (Exception e) {\n            final String savePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath() + System.currentTimeMillis() + \".jpg\";\n            new Thread() {\n                @Override\n                public void run() {\n                    LuaHttp.downloadFile(uri, savePath, headers);\n                }\n            }.start();\n            LuaToast.show(\"正在保存...\");\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode,\n                                           String permissions[], int[] grantResults) {\n        switch (requestCode) {\n            case 0x200: {\n                // If request is cancelled, the result arrays are empty.\n                if (grantResults.length > 0\n                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                    Toast.makeText(this, \"授权成功\", Toast.LENGTH_SHORT).show();\n                }\n            }\n        }\n    }\n\n    private void requestPermission() {\n        ActivityCompat.requestPermissions(this,\n                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},\n                0x200);\n    }\n\n\n    public static class PicturePreviewFragment extends BaseFragment {\n        private View.OnClickListener listener;\n        private SubsamplingScaleImageView iv_big;\n        private ImageView iv_small;\n        private View loading;\n\n        public static PicturePreviewFragment newInstance(String uri, ArrayList<String> headerList) {\n            Bundle args = new Bundle();\n            args.putString(\"uri\", uri);\n            args.putStringArrayList(\"headers\", headerList);\n            PicturePreviewFragment fragment = new PicturePreviewFragment();\n            fragment.setArguments(args);\n            return fragment;\n        }\n\n        public static PicturePreviewFragment newInstance(String uri) {\n            Bundle args = new Bundle();\n            args.putString(\"uri\", uri);\n            PicturePreviewFragment fragment = new PicturePreviewFragment();\n            fragment.setArguments(args);\n            return fragment;\n        }\n\n        public void setOnClickImageListener(View.OnClickListener listener) {\n            this.listener = listener;\n        }\n\n\n        @Nullable\n        @Override\n        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n            return inflater.inflate(R.layout.item_pager_image, container, false);\n        }\n\n\n        @Override\n        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {\n            super.onViewCreated(view, savedInstanceState);\n            final ArrayList<String> headerList = getArguments().getStringArrayList(\"headers\");\n            final String uri = getArguments().getString(\"uri\", \"\");\n            if (LuaStringUtils.isEmpty(uri)) {\n                return;\n            }\n            iv_big = (SubsamplingScaleImageView) view.findViewById(R.id.iv_big);\n            iv_small = (ImageView) view.findViewById(R.id.iv_small);\n            loading = view.findViewById(R.id.loading);\n            loading.setVisibility(View.VISIBLE);\n            iv_small.setOnClickListener(new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    if (listener != null) {\n                        listener.onClick(v);\n                    }\n                }\n            });\n            iv_big.setOnClickListener(new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    if (listener != null) {\n                        listener.onClick(v);\n                    }\n                }\n            });\n\n\n            LazyHeaders.Builder builder = new LazyHeaders.Builder();\n            if (headerList != null) {\n                for (String header : headerList) {\n                    int i = header.indexOf(\":\");\n                    if (i <= 0) {\n                        continue;\n                    }\n                    String key = header.substring(0, i);\n                    String v = header.substring(i + 1);\n                    builder.addHeader(key, v);\n                }\n            }\n            Glide.with(iv_big.getContext())\n                    .load(new GlideUrl(uri, builder.build()))\n                    .downloadOnly(new SimpleTarget<File>() {\n                        @Override\n                        public void onResourceReady(File resource, GlideAnimation<? super File> glideAnimation) {\n                            loadFile(resource);\n                        }\n\n                        @Override\n                        public void onLoadFailed(Exception e, Drawable errorDrawable) {\n                            super.onLoadFailed(e, errorDrawable);\n                            hideLoading();\n                        }\n                    });\n//                    .diskCacheStrategy(DiskCacheStrategy.SOURCE)\n//                    .placeholder(R.drawable.bg_circle)\n//                    .error(R.drawable.bg_circle)\n//                    .crossFade()\n//                    .into(iv_big);\n        }\n\n        private void hideLoading() {\n            if (loading != null) {\n                loading.setVisibility(View.GONE);\n            }\n        }\n\n        public void getImageSize(File file, int[] size) {\n            BitmapFactory.Options options = new BitmapFactory.Options();\n            options.inJustDecodeBounds = true;\n            BitmapFactory.decodeFile(file.getAbsolutePath(), options);\n            size[0] = options.outWidth;\n            size[1] = options.outHeight;\n        }\n\n        public void loadFile(File file) {\n            if (iv_big == null || loading == null) {\n                return;\n            }\n\n            if (file == null || !file.exists()) {\n                LuaToast.show(\"加载失败..\");\n                hideLoading();\n                return;\n            }\n\n            if (\"gif\".equals(LuaFileUtils.getFileType(file.getAbsolutePath()))) {\n                iv_small.setVisibility(View.VISIBLE);\n                iv_big.setVisibility(View.GONE);\n                Glide.with(this).load(file).diskCacheStrategy(DiskCacheStrategy.SOURCE).into(iv_small);\n                hideLoading();\n                return;\n            }\n\n            iv_small.setVisibility(View.GONE);\n            iv_big.setVisibility(View.VISIBLE);\n\n            int[] size = new int[2];\n            getImageSize(file, size);\n            float scale = iv_big.getWidth() * 1.0f / size[0];\n            ImageViewState state = new ImageViewState(scale, new PointF(0, 0), 0);\n            iv_big.setImage(ImageSource.uri(Uri.fromFile(file)), state);\n            hideLoading();\n        }\n    }\n\n    @Override\n    public void finish() {\n        super.finish();\n        overridePendingTransition(0, android.R.anim.fade_out);//结束的动画\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/statusbar/FixInsetsFrameLayout.java",
    "content": "package androlua.widget.statusbar;\n\nimport android.content.Context;\nimport android.graphics.Rect;\nimport android.os.Build;\nimport android.util.AttributeSet;\nimport android.view.WindowInsets;\nimport android.widget.FrameLayout;\n\n/**\n * @author Kevin\n *         Date Created: 3/7/14\n *         <p>\n *         https://code.google.com/p/android/issues/detail?id=63777\n *         <p>\n *         When using a translucent status bar on API 19+, the window will not\n *         resize to make room for input methods (i.e.\n *         {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} and\n *         {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_PAN} are\n *         ignored).\n *         <p>\n *         To work around this; override {@link #fitSystemWindows(Rect)},\n *         capture and override the system insets, and then call through to FrameLayout's\n *         implementation.\n *         <p>\n *         For reasons yet unknown, modifying the bottom inset causes this workaround to\n *         fail. Modifying the top, left, and right insets works as expected.\n */\npublic final class FixInsetsFrameLayout extends FrameLayout {\n    private int[] mInsets = new int[4];\n\n    public FixInsetsFrameLayout(Context context) {\n        super(context);\n    }\n\n    public FixInsetsFrameLayout(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public FixInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n    }\n\n    private boolean insetEnable = false;\n\n    public void setInsetEnable(boolean insetEnable) {\n        this.insetEnable = insetEnable;\n    }\n\n    @Override\n    protected final boolean fitSystemWindows(Rect insets) {\n        if (!insetEnable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            // Intentionally do not modify the bottom inset. For some reason,\n            // if the bottom inset is modified, window resizing stops working.\n\n            mInsets[0] = insets.left;\n            mInsets[1] = insets.top;\n            mInsets[2] = insets.right;\n\n            insets.left = 0;\n            insets.top = 0;\n            insets.right = 0;\n        }\n\n        return super.fitSystemWindows(insets);\n    }\n\n    @Override\n    public final WindowInsets onApplyWindowInsets(WindowInsets insets) {\n        if (!insetEnable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            mInsets[0] = insets.getSystemWindowInsetLeft();\n            mInsets[1] = insets.getSystemWindowInsetTop();\n            mInsets[2] = insets.getSystemWindowInsetRight();\n            return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0,\n                    insets.getSystemWindowInsetBottom()));\n        } else {\n            return insets;\n        }\n    }\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/statusbar/StatusBarView.java",
    "content": "package androlua.widget.statusbar;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.util.AttributeSet;\nimport android.view.View;\n\n\n/**\n * StatusBarView\n * Created by hanks on 18-4-17.\n */\n\npublic class StatusBarView extends View {\n    private int statusBarColor;\n    private int statusBarHeight;\n\n    public StatusBarView(Context context) {\n        this(context, null);\n    }\n\n    public StatusBarView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public StatusBarView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        statusBarColor = Color.BLACK;\n        statusBarHeight = getStatusBarHeight(context);\n    }\n\n    public void setStatusBarColor(int statusBarColor) {\n        this.statusBarColor = statusBarColor;\n        invalidate();\n    }\n\n    public void setStatusBarHeight(int statusBarHeight) {\n        this.statusBarHeight = statusBarHeight;\n        getLayoutParams().height = statusBarHeight;\n        requestLayout();\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        canvas.drawColor(statusBarColor);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        setMeasuredDimension(widthMeasureSpec, statusBarHeight);\n    }\n\n    private int getStatusBarHeight(Context context) {\n        if (Build.VERSION.SDK_INT < 21) {\n            return 0;\n        }\n        int result = 0;\n        int resourceId = context.getResources().getIdentifier(\"status_bar_height\", \"dimen\", \"android\");\n        if (resourceId > 0) {\n            result = context.getResources().getDimensionPixelSize(resourceId);\n        }\n        return result;\n    }\n\n    private int getNavigationBarHeight(Context context) {\n        int result = 0;\n        int resourceId = context.getResources().getIdentifier(\"navigation_bar_height\", \"dimen\", \"android\");\n        if (resourceId > 0) {\n            result = context.getResources().getDimensionPixelSize(resourceId);\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/swipebacklayout/SwipeBackLayout.java",
    "content": "package androlua.widget.swipebacklayout;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.support.v4.view.ViewCompat;\nimport android.util.AttributeSet;\nimport android.util.DisplayMetrics;\nimport android.util.TypedValue;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.WindowManager;\nimport android.widget.FrameLayout;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport pub.hanks.luajandroid.R;\n\n\npublic class SwipeBackLayout extends FrameLayout {\n    /**\n     * Edge flag indicating that the left edge should be affected.\n     */\n    public static final int EDGE_LEFT = ViewDragHelper.EDGE_LEFT;\n    /**\n     * Edge flag indicating that the right edge should be affected.\n     */\n    public static final int EDGE_RIGHT = ViewDragHelper.EDGE_RIGHT;\n    /**\n     * Edge flag indicating that the bottom edge should be affected.\n     */\n    public static final int EDGE_BOTTOM = ViewDragHelper.EDGE_BOTTOM;\n    /**\n     * Edge flag set indicating all edges should be affected.\n     */\n    public static final int EDGE_ALL = EDGE_LEFT | EDGE_RIGHT | EDGE_BOTTOM;\n    /**\n     * A view is not currently being dragged or animating as a result of a\n     * fling/snap.\n     */\n    public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE;\n    /**\n     * A view is currently being dragged. The position is currently changing as\n     * a result of user input or simulated user input.\n     */\n    public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING;\n    /**\n     * A view is currently settling into place as a result of a fling or\n     * predefined non-interactive motion.\n     */\n    public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING;\n    /**\n     * Minimum velocity that will be detected as a fling\n     */\n    private static final int MIN_FLING_VELOCITY = 400; // dips per second\n    private static final int DEFAULT_SCRIM_COLOR = 0x99000000;\n    private static final int FULL_ALPHA = 255;\n    /**\n     * Default threshold of scroll\n     */\n    private static final float DEFAULT_SCROLL_THRESHOLD = 0.3f;\n\n    private static final int OVERSCROLL_DISTANCE = 10;\n\n    private static final int[] EDGE_FLAGS = {\n            EDGE_LEFT, EDGE_RIGHT, EDGE_BOTTOM, EDGE_ALL\n    };\n\n    private int mEdgeFlag;\n\n    /**\n     * Threshold of scroll, we will close the activity, when scrollPercent over\n     * this value;\n     */\n    private float mScrollThreshold = DEFAULT_SCROLL_THRESHOLD;\n\n    private Activity mActivity;\n\n    private boolean mEnable = true;\n\n    private View mContentView;\n\n    private ViewDragHelper mDragHelper;\n\n    private float mScrollPercent;\n\n    private int mContentLeft;\n\n    private int mContentTop;\n\n    /**\n     * The set of listeners to be sent events through.\n     */\n    private List<SwipeListener> mListeners;\n\n    private Drawable mShadowLeft;\n\n    private Drawable mShadowRight;\n\n    private Drawable mShadowBottom;\n\n    private float mScrimOpacity;\n\n    private int mScrimColor = DEFAULT_SCRIM_COLOR;\n\n    private boolean mInLayout;\n\n    private Rect mTmpRect = new Rect();\n\n    /**\n     * Edge being dragged\n     */\n    private int mTrackingEdge;\n\n    public SwipeBackLayout(Context context) {\n        this(context, null);\n    }\n\n    public SwipeBackLayout(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public SwipeBackLayout(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs);\n        mDragHelper = ViewDragHelper.create(this, new ViewDragCallback());\n        setEdgeSize(dp2px(50));\n        int mode = EDGE_FLAGS[0];\n        setEdgeTrackingEnabled(mode);\n        int shadowLeft = R.drawable.shadow_left;\n        int shadowRight = R.drawable.shadow_right;\n        int shadowBottom = R.drawable.shadow_bottom;\n        setShadow(shadowLeft, EDGE_LEFT);\n        setShadow(shadowRight, EDGE_RIGHT);\n        setShadow(shadowBottom, EDGE_BOTTOM);\n        final float density = getResources().getDisplayMetrics().density;\n        final float minVel = MIN_FLING_VELOCITY * density;\n        mDragHelper.setMinVelocity(minVel);\n        mDragHelper.setMaxVelocity(minVel * 2f);\n    }\n\n    private int dp2px(float dp) {\n        DisplayMetrics metrics = new DisplayMetrics();\n        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);\n        wm.getDefaultDisplay().getMetrics(metrics);\n        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics);\n    }\n\n    /**\n     * Sets the sensitivity of the NavigationLayout.\n     *\n     * @param context     The application context.\n     * @param sensitivity value between 0 and 1, the final value for touchSlop =\n     *                    ViewConfiguration.getScaledTouchSlop * (1 / s);\n     */\n    public void setSensitivity(Context context, float sensitivity) {\n        mDragHelper.setSensitivity(context, sensitivity);\n    }\n\n    /**\n     * Set up contentView which will be moved by user gesture\n     *\n     * @param view\n     */\n    private void setContentView(View view) {\n        mContentView = view;\n    }\n\n    public void setEnableGesture(boolean enable) {\n        mEnable = enable;\n    }\n\n    /**\n     * Enable edge tracking for the selected edges of the parent view. The\n     * callback's\n     * {@link ViewDragHelper.Callback#onEdgeTouched(int, int)}\n     * and\n     * {@link ViewDragHelper.Callback#onEdgeDragStarted(int, int)}\n     * methods will only be invoked for edges for which edge tracking has been\n     * enabled.\n     *\n     * @param edgeFlags Combination of edge flags describing the edges to watch\n     * @see #EDGE_LEFT\n     * @see #EDGE_RIGHT\n     * @see #EDGE_BOTTOM\n     */\n    public void setEdgeTrackingEnabled(int edgeFlags) {\n        mEdgeFlag = edgeFlags;\n        mDragHelper.setEdgeTrackingEnabled(mEdgeFlag);\n    }\n\n    /**\n     * Set a color to use for the scrim that obscures primary content while a\n     * drawer is open.\n     *\n     * @param color Color to use in 0xAARRGGBB format.\n     */\n    public void setScrimColor(int color) {\n        mScrimColor = color;\n        invalidate();\n    }\n\n    /**\n     * Set the size of an edge. This is the range in pixels along the edges of\n     * this view that will actively detect edge touches or drags if edge\n     * tracking is enabled.\n     *\n     * @param size The size of an edge in pixels\n     */\n    public void setEdgeSize(int size) {\n        mDragHelper.setEdgeSize(size);\n    }\n\n    /**\n     * Register a callback to be invoked when a swipe event is sent to this\n     * view.\n     *\n     * @param listener the swipe listener to attach to this view\n     * @deprecated use {@link #addSwipeListener} instead\n     */\n    @Deprecated\n    public void setSwipeListener(SwipeListener listener) {\n        addSwipeListener(listener);\n    }\n\n    /**\n     * Add a callback to be invoked when a swipe event is sent to this view.\n     *\n     * @param listener the swipe listener to attach to this view\n     */\n    public void addSwipeListener(SwipeListener listener) {\n        if (mListeners == null) {\n            mListeners = new ArrayList<SwipeListener>();\n        }\n        mListeners.add(listener);\n    }\n\n    /**\n     * Removes a listener from the set of listeners\n     *\n     * @param listener\n     */\n    public void removeSwipeListener(SwipeListener listener) {\n        if (mListeners == null) {\n            return;\n        }\n        mListeners.remove(listener);\n    }\n\n    /**\n     * Set scroll threshold, we will close the activity, when scrollPercent over\n     * this value\n     *\n     * @param threshold\n     */\n    public void setScrollThresHold(float threshold) {\n        if (threshold >= 1.0f || threshold <= 0) {\n            throw new IllegalArgumentException(\"Threshold value should be between 0 and 1.0\");\n        }\n        mScrollThreshold = threshold;\n    }\n\n    /**\n     * Set a drawable used for edge shadow.\n     *\n     * @param shadow Drawable to use\n     * @see #EDGE_LEFT\n     * @see #EDGE_RIGHT\n     * @see #EDGE_BOTTOM\n     */\n    public void setShadow(Drawable shadow, int edgeFlag) {\n        if ((edgeFlag & EDGE_LEFT) != 0) {\n            mShadowLeft = shadow;\n        } else if ((edgeFlag & EDGE_RIGHT) != 0) {\n            mShadowRight = shadow;\n        } else if ((edgeFlag & EDGE_BOTTOM) != 0) {\n            mShadowBottom = shadow;\n        }\n        invalidate();\n    }\n\n    /**\n     * Set a drawable used for edge shadow.\n     *\n     * @param resId Resource of drawable to use\n     * @see #EDGE_LEFT\n     * @see #EDGE_RIGHT\n     * @see #EDGE_BOTTOM\n     */\n    public void setShadow(int resId, int edgeFlag) {\n        setShadow(getResources().getDrawable(resId), edgeFlag);\n    }\n\n    /**\n     * Scroll out contentView and finish the activity\n     */\n    public void scrollToFinishActivity() {\n        final int childWidth = mContentView.getWidth();\n        final int childHeight = mContentView.getHeight();\n\n        int left = 0, top = 0;\n        if ((mEdgeFlag & EDGE_LEFT) != 0) {\n            left = childWidth + mShadowLeft.getIntrinsicWidth() + OVERSCROLL_DISTANCE;\n            mTrackingEdge = EDGE_LEFT;\n        } else if ((mEdgeFlag & EDGE_RIGHT) != 0) {\n            left = -childWidth - mShadowRight.getIntrinsicWidth() - OVERSCROLL_DISTANCE;\n            mTrackingEdge = EDGE_RIGHT;\n        } else if ((mEdgeFlag & EDGE_BOTTOM) != 0) {\n            top = -childHeight - mShadowBottom.getIntrinsicHeight() - OVERSCROLL_DISTANCE;\n            mTrackingEdge = EDGE_BOTTOM;\n        }\n\n        mDragHelper.smoothSlideViewTo(mContentView, left, top);\n        invalidate();\n    }\n\n    @Override\n    public boolean onInterceptTouchEvent(MotionEvent event) {\n        if (!mEnable) {\n            return false;\n        }\n        try {\n            return mDragHelper.shouldInterceptTouchEvent(event);\n        } catch (ArrayIndexOutOfBoundsException e) {\n            // FIXME: handle exception\n            // issues #9\n            return false;\n        }\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent event) {\n        if (!mEnable) {\n            return false;\n        }\n        mDragHelper.processTouchEvent(event);\n        return true;\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\n        mInLayout = true;\n        if (mContentView != null)\n            mContentView.layout(mContentLeft, mContentTop,\n                    mContentLeft + mContentView.getMeasuredWidth(),\n                    mContentTop + mContentView.getMeasuredHeight());\n        mInLayout = false;\n    }\n\n    @Override\n    public void requestLayout() {\n        if (!mInLayout) {\n            super.requestLayout();\n        }\n    }\n\n    @Override\n    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {\n        final boolean drawContent = child == mContentView;\n\n        boolean ret = super.drawChild(canvas, child, drawingTime);\n        if (mScrimOpacity > 0 && drawContent\n                && mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE) {\n            drawShadow(canvas, child);\n            drawScrim(canvas, child);\n        }\n        return ret;\n    }\n\n    private void drawScrim(Canvas canvas, View child) {\n        final int baseAlpha = (mScrimColor & 0xff000000) >>> 24;\n        final int alpha = (int) (baseAlpha * mScrimOpacity);\n        final int color = alpha << 24 | (mScrimColor & 0xffffff);\n\n        if ((mTrackingEdge & EDGE_LEFT) != 0) {\n            canvas.clipRect(0, 0, child.getLeft(), getHeight());\n        } else if ((mTrackingEdge & EDGE_RIGHT) != 0) {\n            canvas.clipRect(child.getRight(), 0, getRight(), getHeight());\n        } else if ((mTrackingEdge & EDGE_BOTTOM) != 0) {\n            canvas.clipRect(child.getLeft(), child.getBottom(), getRight(), getHeight());\n        }\n        canvas.drawColor(color);\n    }\n\n    private void drawShadow(Canvas canvas, View child) {\n        final Rect childRect = mTmpRect;\n        child.getHitRect(childRect);\n\n        if ((mEdgeFlag & EDGE_LEFT) != 0) {\n            mShadowLeft.setBounds(childRect.left - mShadowLeft.getIntrinsicWidth(), childRect.top,\n                    childRect.left, childRect.bottom);\n            mShadowLeft.setAlpha((int) (mScrimOpacity * FULL_ALPHA));\n            mShadowLeft.draw(canvas);\n        }\n\n        if ((mEdgeFlag & EDGE_RIGHT) != 0) {\n            mShadowRight.setBounds(childRect.right, childRect.top,\n                    childRect.right + mShadowRight.getIntrinsicWidth(), childRect.bottom);\n            mShadowRight.setAlpha((int) (mScrimOpacity * FULL_ALPHA));\n            mShadowRight.draw(canvas);\n        }\n\n        if ((mEdgeFlag & EDGE_BOTTOM) != 0) {\n            mShadowBottom.setBounds(childRect.left, childRect.bottom, childRect.right,\n                    childRect.bottom + mShadowBottom.getIntrinsicHeight());\n            mShadowBottom.setAlpha((int) (mScrimOpacity * FULL_ALPHA));\n            mShadowBottom.draw(canvas);\n        }\n    }\n\n    public void attachToActivity(Activity activity) {\n        mActivity = activity;\n        TypedArray a = activity.getTheme().obtainStyledAttributes(new int[]{\n                android.R.attr.windowBackground\n        });\n        int background = a.getResourceId(0, 0);\n        a.recycle();\n\n        ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();\n        ViewGroup decorChild = (ViewGroup) decor.getChildAt(0);\n        decorChild.setBackgroundResource(background);\n        decor.removeView(decorChild);\n        addView(decorChild);\n        setContentView(decorChild);\n        decor.addView(this);\n    }\n\n    @Override\n    public void computeScroll() {\n        mScrimOpacity = 1 - mScrollPercent;\n        if (mDragHelper.continueSettling(true)) {\n            ViewCompat.postInvalidateOnAnimation(this);\n        }\n    }\n\n    public static interface SwipeListener {\n        /**\n         * Invoke when state change\n         *\n         * @param state         flag to describe scroll state\n         * @param scrollPercent scroll percent of this view\n         * @see #STATE_IDLE\n         * @see #STATE_DRAGGING\n         * @see #STATE_SETTLING\n         */\n        public void onScrollStateChange(int state, float scrollPercent);\n\n        /**\n         * Invoke when edge touched\n         *\n         * @param edgeFlag edge flag describing the edge being touched\n         * @see #EDGE_LEFT\n         * @see #EDGE_RIGHT\n         * @see #EDGE_BOTTOM\n         */\n        public void onEdgeTouch(int edgeFlag);\n\n        /**\n         * Invoke when scroll percent over the threshold for the first time\n         */\n        public void onScrollOverThreshold();\n    }\n\n    private class ViewDragCallback extends ViewDragHelper.Callback {\n        private boolean mIsScrollOverValid;\n\n        @Override\n        public boolean tryCaptureView(View view, int i) {\n            boolean ret = mDragHelper.isEdgeTouched(mEdgeFlag, i);\n            if (ret) {\n                if (mDragHelper.isEdgeTouched(EDGE_LEFT, i)) {\n                    mTrackingEdge = EDGE_LEFT;\n                } else if (mDragHelper.isEdgeTouched(EDGE_RIGHT, i)) {\n                    mTrackingEdge = EDGE_RIGHT;\n                } else if (mDragHelper.isEdgeTouched(EDGE_BOTTOM, i)) {\n                    mTrackingEdge = EDGE_BOTTOM;\n                }\n                if (mListeners != null && !mListeners.isEmpty()) {\n                    for (SwipeListener listener : mListeners) {\n                        listener.onEdgeTouch(mTrackingEdge);\n                    }\n                }\n                mIsScrollOverValid = true;\n            }\n            return ret;\n        }\n\n        @Override\n        public int getViewHorizontalDragRange(View child) {\n            return mEdgeFlag & (EDGE_LEFT | EDGE_RIGHT);\n        }\n\n        @Override\n        public int getViewVerticalDragRange(View child) {\n            return mEdgeFlag & EDGE_BOTTOM;\n        }\n\n        @Override\n        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {\n            super.onViewPositionChanged(changedView, left, top, dx, dy);\n            if ((mTrackingEdge & EDGE_LEFT) != 0) {\n                mScrollPercent = Math.abs((float) left\n                        / (mContentView.getWidth() + mShadowLeft.getIntrinsicWidth()));\n            } else if ((mTrackingEdge & EDGE_RIGHT) != 0) {\n                mScrollPercent = Math.abs((float) left\n                        / (mContentView.getWidth() + mShadowRight.getIntrinsicWidth()));\n            } else if ((mTrackingEdge & EDGE_BOTTOM) != 0) {\n                mScrollPercent = Math.abs((float) top\n                        / (mContentView.getHeight() + mShadowBottom.getIntrinsicHeight()));\n            }\n            mContentLeft = left;\n            mContentTop = top;\n            invalidate();\n            if (mScrollPercent < mScrollThreshold && !mIsScrollOverValid) {\n                mIsScrollOverValid = true;\n            }\n            if (mListeners != null && !mListeners.isEmpty()\n                    && mDragHelper.getViewDragState() == STATE_DRAGGING\n                    && mScrollPercent >= mScrollThreshold && mIsScrollOverValid) {\n                mIsScrollOverValid = false;\n                for (SwipeListener listener : mListeners) {\n                    listener.onScrollOverThreshold();\n                }\n            }\n\n            if (mScrollPercent >= 1) {\n                if (!mActivity.isFinishing()) {\n                    mActivity.finish();\n                    mActivity.overridePendingTransition(0, 0);\n                }\n            }\n        }\n\n        @Override\n        public void onViewReleased(View releasedChild, float xvel, float yvel) {\n            final int childWidth = releasedChild.getWidth();\n            final int childHeight = releasedChild.getHeight();\n\n            int left = 0, top = 0;\n            if ((mTrackingEdge & EDGE_LEFT) != 0) {\n                left = xvel > 0 || xvel == 0 && mScrollPercent > mScrollThreshold ? childWidth\n                        + mShadowLeft.getIntrinsicWidth() + OVERSCROLL_DISTANCE : 0;\n            } else if ((mTrackingEdge & EDGE_RIGHT) != 0) {\n                left = xvel < 0 || xvel == 0 && mScrollPercent > mScrollThreshold ? -(childWidth\n                        + mShadowLeft.getIntrinsicWidth() + OVERSCROLL_DISTANCE) : 0;\n            } else if ((mTrackingEdge & EDGE_BOTTOM) != 0) {\n                top = yvel < 0 || yvel == 0 && mScrollPercent > mScrollThreshold ? -(childHeight\n                        + mShadowBottom.getIntrinsicHeight() + OVERSCROLL_DISTANCE) : 0;\n            }\n\n            mDragHelper.settleCapturedViewAt(left, top);\n            invalidate();\n        }\n\n        @Override\n        public int clampViewPositionHorizontal(View child, int left, int dx) {\n            int ret = 0;\n            if ((mTrackingEdge & EDGE_LEFT) != 0) {\n                ret = Math.min(child.getWidth(), Math.max(left, 0));\n            } else if ((mTrackingEdge & EDGE_RIGHT) != 0) {\n                ret = Math.min(0, Math.max(left, -child.getWidth()));\n            }\n            return ret;\n        }\n\n        @Override\n        public int clampViewPositionVertical(View child, int top, int dy) {\n            int ret = 0;\n            if ((mTrackingEdge & EDGE_BOTTOM) != 0) {\n                ret = Math.min(0, Math.max(top, -child.getHeight()));\n            }\n            return ret;\n        }\n\n        @Override\n        public void onViewDragStateChanged(int state) {\n            super.onViewDragStateChanged(state);\n            if (mListeners != null && !mListeners.isEmpty()) {\n                for (SwipeListener listener : mListeners) {\n                    listener.onScrollStateChange(state, mScrollPercent);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/swipebacklayout/Utils.java",
    "content": "package androlua.widget.swipebacklayout;\n\nimport android.app.Activity;\n\nimport java.lang.reflect.Method;\n\n/**\n * Created by Chaojun Wang on 6/9/14.\n */\npublic class Utils {\n    private Utils() {\n    }\n\n    /**\n     * Convert a translucent themed Activity\n     * {@link android.R.attr#windowIsTranslucent} to a fullscreen opaque\n     * Activity.\n     * <p>\n     * Call this whenever the background of a translucent Activity has changed\n     * to become opaque. Doing so will allow the {@link android.view.Surface} of\n     * the Activity behind to be released.\n     * <p>\n     * This call has no effect on non-translucent activities or on activities\n     * with the {@link android.R.attr#windowIsFloating} attribute.\n     */\n    public static void convertActivityFromTranslucent(Activity activity) {\n        try {\n            Method method = Activity.class.getDeclaredMethod(\"convertFromTranslucent\");\n            method.setAccessible(true);\n            method.invoke(activity);\n        } catch (Throwable t) {\n        }\n    }\n\n    /**\n     * Convert a translucent themed Activity\n     * {@link android.R.attr#windowIsTranslucent} back from opaque to\n     * translucent following a call to\n     * {@link #convertActivityFromTranslucent(Activity)} .\n     * <p>\n     * Calling this allows the Activity behind this one to be seen again. Once\n     * all such Activities have been redrawn\n     * <p>\n     * This call has no effect on non-translucent activities or on activities\n     * with the {@link android.R.attr#windowIsFloating} attribute.\n     */\n    public static void convertActivityToTranslucent(Activity activity) {\n        try {\n            Class<?>[] classes = Activity.class.getDeclaredClasses();\n            Class<?> translucentConversionListenerClazz = null;\n            for (Class clazz : classes) {\n                if (clazz.getSimpleName().contains(\"TranslucentConversionListener\")) {\n                    translucentConversionListenerClazz = clazz;\n                }\n            }\n            Method method = Activity.class.getDeclaredMethod(\"convertToTranslucent\",\n                    translucentConversionListenerClazz);\n            method.setAccessible(true);\n            method.invoke(activity, new Object[]{\n                    null\n            });\n        } catch (Throwable t) {\n        }\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/swipebacklayout/ViewDragHelper.java",
    "content": "/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage androlua.widget.swipebacklayout;\n\nimport android.content.Context;\nimport android.support.v4.view.MotionEventCompat;\nimport android.support.v4.view.VelocityTrackerCompat;\nimport android.support.v4.view.ViewCompat;\nimport android.support.v4.widget.ScrollerCompat;\nimport android.util.Log;\nimport android.view.MotionEvent;\nimport android.view.VelocityTracker;\nimport android.view.View;\nimport android.view.ViewConfiguration;\nimport android.view.ViewGroup;\nimport android.view.animation.Interpolator;\n\nimport java.util.Arrays;\n\n/**\n * ViewDragHelper is a utility class for writing custom ViewGroups. It offers a\n * number of useful operations and state tracking for allowing a user to drag\n * and reposition views within their parent ViewGroup.\n */\npublic class ViewDragHelper {\n    /**\n     * A null/invalid pointer ID.\n     */\n    public static final int INVALID_POINTER = -1;\n    /**\n     * A view is not currently being dragged or animating as a result of a\n     * fling/snap.\n     */\n    public static final int STATE_IDLE = 0;\n    /**\n     * A view is currently being dragged. The position is currently changing as\n     * a result of user input or simulated user input.\n     */\n    public static final int STATE_DRAGGING = 1;\n    /**\n     * A view is currently settling into place as a result of a fling or\n     * predefined non-interactive motion.\n     */\n    public static final int STATE_SETTLING = 2;\n    /**\n     * Edge flag indicating that the left edge should be affected.\n     */\n    public static final int EDGE_LEFT = 1 << 0;\n    /**\n     * Edge flag indicating that the right edge should be affected.\n     */\n    public static final int EDGE_RIGHT = 1 << 1;\n    /**\n     * Edge flag indicating that the top edge should be affected.\n     */\n    public static final int EDGE_TOP = 1 << 2;\n    /**\n     * Edge flag indicating that the bottom edge should be affected.\n     */\n    public static final int EDGE_BOTTOM = 1 << 3;\n    /**\n     * Edge flag set indicating all edges should be affected.\n     */\n    public static final int EDGE_ALL = EDGE_LEFT | EDGE_TOP | EDGE_RIGHT | EDGE_BOTTOM;\n    /**\n     * Indicates that a check should occur along the horizontal axis\n     */\n    public static final int DIRECTION_HORIZONTAL = 1 << 0;\n    /**\n     * Indicates that a check should occur along the vertical axis\n     */\n    public static final int DIRECTION_VERTICAL = 1 << 1;\n    /**\n     * Indicates that a check should occur along all axes\n     */\n    public static final int DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;\n    public static final int EDGE_SIZE = 20; // dp\n    private static final String TAG = \"ViewDragHelper\";\n    private static final int BASE_SETTLE_DURATION = 256; // ms\n\n    private static final int MAX_SETTLE_DURATION = 600; // ms\n    /**\n     * Interpolator defining the animation curve for mScroller\n     */\n    private static final Interpolator sInterpolator = new Interpolator() {\n        public float getInterpolation(float t) {\n            t -= 1.0f;\n            return t * t * t * t * t + 1.0f;\n        }\n    };\n    private final Callback mCallback;\n    private final ViewGroup mParentView;\n    // Current drag state; idle, dragging or settling\n    private int mDragState;\n    // Distance to travel before a drag may begin\n    private int mTouchSlop;\n    // Last known position/pointer tracking\n    private int mActivePointerId = INVALID_POINTER;\n    private float[] mInitialMotionX;\n    private float[] mInitialMotionY;\n    private float[] mLastMotionX;\n    private float[] mLastMotionY;\n    private int[] mInitialEdgeTouched;\n    private int[] mEdgeDragsInProgress;\n    private int[] mEdgeDragsLocked;\n    private int mPointersDown;\n    private VelocityTracker mVelocityTracker;\n    private float mMaxVelocity;\n    private float mMinVelocity;\n    private int mEdgeSize;\n    private int mTrackingEdges;\n    private ScrollerCompat mScroller;\n    private View mCapturedView;\n    private final Runnable mSetIdleRunnable = new Runnable() {\n        public void run() {\n            setDragState(STATE_IDLE);\n        }\n    };\n    private boolean mReleaseInProgress;\n\n    /**\n     * Apps should use ViewDragHelper.create() to get a new instance. This will\n     * allow VDH to use internal compatibility implementations for different\n     * platform versions.\n     *\n     * @param context   Context to initialize config-dependent params from\n     * @param forParent Parent view to monitor\n     */\n    private ViewDragHelper(Context context, ViewGroup forParent, Callback cb) {\n        if (forParent == null) {\n            throw new IllegalArgumentException(\"Parent view may not be null\");\n        }\n        if (cb == null) {\n            throw new IllegalArgumentException(\"Callback may not be null\");\n        }\n\n        mParentView = forParent;\n        mCallback = cb;\n\n        final ViewConfiguration vc = ViewConfiguration.get(context);\n        final float density = context.getResources().getDisplayMetrics().density;\n        mEdgeSize = (int) (EDGE_SIZE * density + 0.5f);\n\n        mTouchSlop = vc.getScaledTouchSlop();\n        mMaxVelocity = vc.getScaledMaximumFlingVelocity();\n        mMinVelocity = vc.getScaledMinimumFlingVelocity();\n        mScroller = ScrollerCompat.create(context, sInterpolator);\n    }\n\n    /**\n     * Factory method to create a new ViewDragHelper.\n     *\n     * @param forParent Parent view to monitor\n     * @param cb        Callback to provide information and receive events\n     * @return a new ViewDragHelper instance\n     */\n    public static ViewDragHelper create(ViewGroup forParent, Callback cb) {\n        return new ViewDragHelper(forParent.getContext(), forParent, cb);\n    }\n\n    /**\n     * Factory method to create a new ViewDragHelper.\n     *\n     * @param forParent   Parent view to monitor\n     * @param sensitivity Multiplier for how sensitive the helper should be\n     *                    about detecting the start of a drag. Larger values are more\n     *                    sensitive. 1.0f is normal.\n     * @param cb          Callback to provide information and receive events\n     * @return a new ViewDragHelper instance\n     */\n    public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb) {\n        final ViewDragHelper helper = create(forParent, cb);\n        helper.mTouchSlop = (int) (helper.mTouchSlop * (1 / sensitivity));\n        return helper;\n    }\n\n    /**\n     * Sets the sensitivity of the dragger.\n     *\n     * @param context     The application context.\n     * @param sensitivity value between 0 and 1, the final value for touchSlop =\n     *                    ViewConfiguration.getScaledTouchSlop * (1 / s);\n     */\n    public void setSensitivity(Context context, float sensitivity) {\n        float s = Math.max(0f, Math.min(1.0f, sensitivity));\n        ViewConfiguration viewConfiguration = ViewConfiguration.get(context);\n        mTouchSlop = (int) (viewConfiguration.getScaledTouchSlop() * (1 / s));\n    }\n\n    /**\n     * Set the max velocity that will be detected as having a magnitude\n     * greater than zero in pixels per second. Callback methods accepting a\n     * velocity will be clamped appropriately.\n     *\n     * @param maxVel max velocity to detect\n     */\n    public void setMaxVelocity(float maxVel) {\n        mMaxVelocity = maxVel;\n    }\n\n    /**\n     * Return the currently configured minimum velocity. Any flings with a\n     * magnitude less than this value in pixels per second. Callback methods\n     * accepting a velocity will receive zero as a velocity value if the real\n     * detected velocity was below this threshold.\n     *\n     * @return the minimum velocity that will be detected\n     */\n    public float getMinVelocity() {\n        return mMinVelocity;\n    }\n\n    /**\n     * Set the minimum velocity that will be detected as having a magnitude\n     * greater than zero in pixels per second. Callback methods accepting a\n     * velocity will be clamped appropriately.\n     *\n     * @param minVel minimum velocity to detect\n     */\n    public void setMinVelocity(float minVel) {\n        mMinVelocity = minVel;\n    }\n\n    /**\n     * Retrieve the current drag state of this helper. This will return one of\n     * {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.\n     *\n     * @return The current drag state\n     */\n    public int getViewDragState() {\n        return mDragState;\n    }\n\n    /**\n     * Enable edge tracking for the selected edges of the parent view. The\n     * callback's\n     * {@link ViewDragHelper.Callback#onEdgeTouched(int, int)}\n     * and\n     * {@link ViewDragHelper.Callback#onEdgeDragStarted(int, int)}\n     * methods will only be invoked for edges for which edge tracking has been\n     * enabled.\n     *\n     * @param edgeFlags Combination of edge flags describing the edges to watch\n     * @see #EDGE_LEFT\n     * @see #EDGE_TOP\n     * @see #EDGE_RIGHT\n     * @see #EDGE_BOTTOM\n     */\n    public void setEdgeTrackingEnabled(int edgeFlags) {\n        mTrackingEdges = edgeFlags;\n    }\n\n    /**\n     * Return the size of an edge. This is the range in pixels along the edges\n     * of this view that will actively detect edge touches or drags if edge\n     * tracking is enabled.\n     *\n     * @return The size of an edge in pixels\n     * @see #setEdgeTrackingEnabled(int)\n     */\n    public int getEdgeSize() {\n        return mEdgeSize;\n    }\n\n    /**\n     * Set the size of an edge. This is the range in pixels along the edges of\n     * this view that will actively detect edge touches or drags if edge\n     * tracking is enabled.\n     *\n     * @param size The size of an edge in pixels\n     */\n    public void setEdgeSize(int size) {\n        mEdgeSize = size;\n    }\n\n    /**\n     * Capture a specific child view for dragging within the parent. The\n     * callback will be notified but\n     * {@link ViewDragHelper.Callback#tryCaptureView(View, int)}\n     * will not be asked permission to capture this view.\n     *\n     * @param childView       Child view to capture\n     * @param activePointerId ID of the pointer that is dragging the captured\n     *                        child view\n     */\n    public void captureChildView(View childView, int activePointerId) {\n        if (childView.getParent() != mParentView) {\n            throw new IllegalArgumentException(\"captureChildView: parameter must be a descendant \"\n                    + \"of the ViewDragHelper's tracked parent view (\" + mParentView + \")\");\n        }\n\n        mCapturedView = childView;\n        mActivePointerId = activePointerId;\n        mCallback.onViewCaptured(childView, activePointerId);\n        setDragState(STATE_DRAGGING);\n    }\n\n    /**\n     * @return The currently captured view, or null if no view has been\n     * captured.\n     */\n    public View getCapturedView() {\n        return mCapturedView;\n    }\n\n    /**\n     * @return The ID of the pointer currently dragging the captured view, or\n     * {@link #INVALID_POINTER}.\n     */\n    public int getActivePointerId() {\n        return mActivePointerId;\n    }\n\n    /**\n     * @return The minimum distance in pixels that the user must travel to\n     * initiate a drag\n     */\n    public int getTouchSlop() {\n        return mTouchSlop;\n    }\n\n    /**\n     * The result of a call to this method is equivalent to\n     * {@link #processTouchEvent(MotionEvent)} receiving an\n     * ACTION_CANCEL event.\n     */\n    public void cancel() {\n        mActivePointerId = INVALID_POINTER;\n        clearMotionHistory();\n\n        if (mVelocityTracker != null) {\n            mVelocityTracker.recycle();\n            mVelocityTracker = null;\n        }\n    }\n\n    /**\n     * {@link #cancel()}, but also abort all motion in progress and snap to the\n     * end of any animation.\n     */\n    public void abort() {\n        cancel();\n        if (mDragState == STATE_SETTLING) {\n            final int oldX = mScroller.getCurrX();\n            final int oldY = mScroller.getCurrY();\n            mScroller.abortAnimation();\n            final int newX = mScroller.getCurrX();\n            final int newY = mScroller.getCurrY();\n            mCallback.onViewPositionChanged(mCapturedView, newX, newY, newX - oldX, newY - oldY);\n        }\n        setDragState(STATE_IDLE);\n    }\n\n    /**\n     * Animate the view <code>child</code> to the given (left, top) position. If\n     * this method returns true, the caller should invoke\n     * {@link #continueSettling(boolean)} on each subsequent frame to continue\n     * the motion until it returns false. If this method returns false there is\n     * no further work to do to complete the movement.\n     * <p>\n     * This operation does not count as a capture event, though\n     * {@link #getCapturedView()} will still report the sliding view while the\n     * slide is in progress.\n     * </p>\n     *\n     * @param child     Child view to capture and animate\n     * @param finalLeft Final left position of child\n     * @param finalTop  Final top position of child\n     * @return true if animation should continue through\n     * {@link #continueSettling(boolean)} calls\n     */\n    public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop) {\n        mCapturedView = child;\n        mActivePointerId = INVALID_POINTER;\n\n        return forceSettleCapturedViewAt(finalLeft, finalTop, 0, 0);\n    }\n\n    /**\n     * Settle the captured view at the given (left, top) position. The\n     * appropriate velocity from prior motion will be taken into account. If\n     * this method returns true, the caller should invoke\n     * {@link #continueSettling(boolean)} on each subsequent frame to continue\n     * the motion until it returns false. If this method returns false there is\n     * no further work to do to complete the movement.\n     *\n     * @param finalLeft Settled left edge position for the captured view\n     * @param finalTop  Settled top edge position for the captured view\n     * @return true if animation should continue through\n     * {@link #continueSettling(boolean)} calls\n     */\n    public boolean settleCapturedViewAt(int finalLeft, int finalTop) {\n        if (!mReleaseInProgress) {\n            throw new IllegalStateException(\"Cannot settleCapturedViewAt outside of a call to \"\n                    + \"Callback#onViewReleased\");\n        }\n\n        return forceSettleCapturedViewAt(finalLeft, finalTop,\n                (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),\n                (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId));\n    }\n\n    /**\n     * Settle the captured view at the given (left, top) position.\n     *\n     * @param finalLeft Target left position for the captured view\n     * @param finalTop  Target top position for the captured view\n     * @param xvel      Horizontal velocity\n     * @param yvel      Vertical velocity\n     * @return true if animation should continue through\n     * {@link #continueSettling(boolean)} calls\n     */\n    private boolean forceSettleCapturedViewAt(int finalLeft, int finalTop, int xvel, int yvel) {\n        final int startLeft = mCapturedView.getLeft();\n        final int startTop = mCapturedView.getTop();\n        final int dx = finalLeft - startLeft;\n        final int dy = finalTop - startTop;\n\n        if (dx == 0 && dy == 0) {\n            // Nothing to do. Send callbacks, be done.\n            mScroller.abortAnimation();\n            setDragState(STATE_IDLE);\n            return false;\n        }\n\n        final int duration = computeSettleDuration(mCapturedView, dx, dy, xvel, yvel);\n        mScroller.startScroll(startLeft, startTop, dx, dy, duration);\n\n        setDragState(STATE_SETTLING);\n        return true;\n    }\n\n    private int computeSettleDuration(View child, int dx, int dy, int xvel, int yvel) {\n        xvel = clampMag(xvel, (int) mMinVelocity, (int) mMaxVelocity);\n        yvel = clampMag(yvel, (int) mMinVelocity, (int) mMaxVelocity);\n        final int absDx = Math.abs(dx);\n        final int absDy = Math.abs(dy);\n        final int absXVel = Math.abs(xvel);\n        final int absYVel = Math.abs(yvel);\n        final int addedVel = absXVel + absYVel;\n        final int addedDistance = absDx + absDy;\n\n        final float xweight = xvel != 0 ? (float) absXVel / addedVel : (float) absDx\n                / addedDistance;\n        final float yweight = yvel != 0 ? (float) absYVel / addedVel : (float) absDy\n                / addedDistance;\n\n        int xduration = computeAxisDuration(dx, xvel, mCallback.getViewHorizontalDragRange(child));\n        int yduration = computeAxisDuration(dy, yvel, mCallback.getViewVerticalDragRange(child));\n\n        return (int) (xduration * xweight + yduration * yweight);\n    }\n\n    private int computeAxisDuration(int delta, int velocity, int motionRange) {\n        if (delta == 0) {\n            return 0;\n        }\n\n        final int width = mParentView.getWidth();\n        final int halfWidth = width / 2;\n        final float distanceRatio = Math.min(1f, (float) Math.abs(delta) / width);\n        final float distance = halfWidth + halfWidth\n                * distanceInfluenceForSnapDuration(distanceRatio);\n\n        int duration;\n        velocity = Math.abs(velocity);\n        if (velocity > 0) {\n            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));\n        } else {\n            final float range = (float) Math.abs(delta) / motionRange;\n            duration = (int) ((range + 1) * BASE_SETTLE_DURATION);\n        }\n        return Math.min(duration, MAX_SETTLE_DURATION);\n    }\n\n    /**\n     * Clamp the magnitude of value for absMin and absMax. If the value is below\n     * the minimum, it will be clamped to zero. If the value is above the\n     * maximum, it will be clamped to the maximum.\n     *\n     * @param value  Value to clamp\n     * @param absMin Absolute value of the minimum significant value to return\n     * @param absMax Absolute value of the maximum value to return\n     * @return The clamped value with the same sign as <code>value</code>\n     */\n    private int clampMag(int value, int absMin, int absMax) {\n        final int absValue = Math.abs(value);\n        if (absValue < absMin)\n            return 0;\n        if (absValue > absMax)\n            return value > 0 ? absMax : -absMax;\n        return value;\n    }\n\n    /**\n     * Clamp the magnitude of value for absMin and absMax. If the value is below\n     * the minimum, it will be clamped to zero. If the value is above the\n     * maximum, it will be clamped to the maximum.\n     *\n     * @param value  Value to clamp\n     * @param absMin Absolute value of the minimum significant value to return\n     * @param absMax Absolute value of the maximum value to return\n     * @return The clamped value with the same sign as <code>value</code>\n     */\n    private float clampMag(float value, float absMin, float absMax) {\n        final float absValue = Math.abs(value);\n        if (absValue < absMin)\n            return 0;\n        if (absValue > absMax)\n            return value > 0 ? absMax : -absMax;\n        return value;\n    }\n\n    private float distanceInfluenceForSnapDuration(float f) {\n        f -= 0.5f; // center the values about 0.\n        f *= 0.3f * Math.PI / 2.0f;\n        return (float) Math.sin(f);\n    }\n\n    /**\n     * Settle the captured view based on standard free-moving fling behavior.\n     * The caller should invoke {@link #continueSettling(boolean)} on each\n     * subsequent frame to continue the motion until it returns false.\n     *\n     * @param minLeft Minimum X position for the view's left edge\n     * @param minTop  Minimum Y position for the view's top edge\n     * @param maxLeft Maximum X position for the view's left edge\n     * @param maxTop  Maximum Y position for the view's top edge\n     */\n    public void flingCapturedView(int minLeft, int minTop, int maxLeft, int maxTop) {\n        if (!mReleaseInProgress) {\n            throw new IllegalStateException(\"Cannot flingCapturedView outside of a call to \"\n                    + \"Callback#onViewReleased\");\n        }\n\n        mScroller.fling(mCapturedView.getLeft(), mCapturedView.getTop(),\n                (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),\n                (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId),\n                minLeft, maxLeft, minTop, maxTop);\n\n        setDragState(STATE_SETTLING);\n    }\n\n    /**\n     * Move the captured settling view by the appropriate amount for the current\n     * time. If <code>continueSettling</code> returns true, the caller should\n     * call it again on the next frame to continue.\n     *\n     * @param deferCallbacks true if state callbacks should be deferred via\n     *                       posted message. Set this to true if you are calling this\n     *                       method from {@link View#computeScroll()} or\n     *                       similar methods invoked as part of layout or drawing.\n     * @return true if settle is still in progress\n     */\n    public boolean continueSettling(boolean deferCallbacks) {\n        if (mDragState == STATE_SETTLING) {\n            boolean keepGoing = mScroller.computeScrollOffset();\n            final int x = mScroller.getCurrX();\n            final int y = mScroller.getCurrY();\n            final int dx = x - mCapturedView.getLeft();\n            final int dy = y - mCapturedView.getTop();\n\n            if (dx != 0) {\n                mCapturedView.offsetLeftAndRight(dx);\n            }\n            if (dy != 0) {\n                mCapturedView.offsetTopAndBottom(dy);\n            }\n\n            if (dx != 0 || dy != 0) {\n                mCallback.onViewPositionChanged(mCapturedView, x, y, dx, dy);\n            }\n\n            if (keepGoing && x == mScroller.getFinalX() && y == mScroller.getFinalY()) {\n                // Close enough. The interpolator/scroller might think we're\n                // still moving\n                // but the user sure doesn't.\n                mScroller.abortAnimation();\n                keepGoing = mScroller.isFinished();\n            }\n\n            if (!keepGoing) {\n                if (deferCallbacks) {\n                    mParentView.post(mSetIdleRunnable);\n                } else {\n                    setDragState(STATE_IDLE);\n                }\n            }\n        }\n\n        return mDragState == STATE_SETTLING;\n    }\n\n    /**\n     * Like all callback events this must happen on the UI thread, but release\n     * involves some extra semantics. During a release (mReleaseInProgress) is\n     * the only time it is valid to call {@link #settleCapturedViewAt(int, int)}\n     * or {@link #flingCapturedView(int, int, int, int)}.\n     */\n    private void dispatchViewReleased(float xvel, float yvel) {\n        mReleaseInProgress = true;\n        mCallback.onViewReleased(mCapturedView, xvel, yvel);\n        mReleaseInProgress = false;\n\n        if (mDragState == STATE_DRAGGING) {\n            // onViewReleased didn't call a method that would have changed this.\n            // Go idle.\n            setDragState(STATE_IDLE);\n        }\n    }\n\n    private void clearMotionHistory() {\n        if (mInitialMotionX == null) {\n            return;\n        }\n        Arrays.fill(mInitialMotionX, 0);\n        Arrays.fill(mInitialMotionY, 0);\n        Arrays.fill(mLastMotionX, 0);\n        Arrays.fill(mLastMotionY, 0);\n        Arrays.fill(mInitialEdgeTouched, 0);\n        Arrays.fill(mEdgeDragsInProgress, 0);\n        Arrays.fill(mEdgeDragsLocked, 0);\n        mPointersDown = 0;\n    }\n\n    private void clearMotionHistory(int pointerId) {\n        if (mInitialMotionX == null) {\n            return;\n        }\n        mInitialMotionX[pointerId] = 0;\n        mInitialMotionY[pointerId] = 0;\n        mLastMotionX[pointerId] = 0;\n        mLastMotionY[pointerId] = 0;\n        mInitialEdgeTouched[pointerId] = 0;\n        mEdgeDragsInProgress[pointerId] = 0;\n        mEdgeDragsLocked[pointerId] = 0;\n        mPointersDown &= ~(1 << pointerId);\n    }\n\n    private void ensureMotionHistorySizeForId(int pointerId) {\n        if (mInitialMotionX == null || mInitialMotionX.length <= pointerId) {\n            float[] imx = new float[pointerId + 1];\n            float[] imy = new float[pointerId + 1];\n            float[] lmx = new float[pointerId + 1];\n            float[] lmy = new float[pointerId + 1];\n            int[] iit = new int[pointerId + 1];\n            int[] edip = new int[pointerId + 1];\n            int[] edl = new int[pointerId + 1];\n\n            if (mInitialMotionX != null) {\n                System.arraycopy(mInitialMotionX, 0, imx, 0, mInitialMotionX.length);\n                System.arraycopy(mInitialMotionY, 0, imy, 0, mInitialMotionY.length);\n                System.arraycopy(mLastMotionX, 0, lmx, 0, mLastMotionX.length);\n                System.arraycopy(mLastMotionY, 0, lmy, 0, mLastMotionY.length);\n                System.arraycopy(mInitialEdgeTouched, 0, iit, 0, mInitialEdgeTouched.length);\n                System.arraycopy(mEdgeDragsInProgress, 0, edip, 0, mEdgeDragsInProgress.length);\n                System.arraycopy(mEdgeDragsLocked, 0, edl, 0, mEdgeDragsLocked.length);\n            }\n\n            mInitialMotionX = imx;\n            mInitialMotionY = imy;\n            mLastMotionX = lmx;\n            mLastMotionY = lmy;\n            mInitialEdgeTouched = iit;\n            mEdgeDragsInProgress = edip;\n            mEdgeDragsLocked = edl;\n        }\n    }\n\n    private void saveInitialMotion(float x, float y, int pointerId) {\n        ensureMotionHistorySizeForId(pointerId);\n        mInitialMotionX[pointerId] = mLastMotionX[pointerId] = x;\n        mInitialMotionY[pointerId] = mLastMotionY[pointerId] = y;\n        mInitialEdgeTouched[pointerId] = getEdgeTouched((int) x, (int) y);\n        mPointersDown |= 1 << pointerId;\n    }\n\n    private void saveLastMotion(MotionEvent ev) {\n        final int pointerCount = MotionEventCompat.getPointerCount(ev);\n        for (int i = 0; i < pointerCount; i++) {\n            final int pointerId = MotionEventCompat.getPointerId(ev, i);\n            final float x = MotionEventCompat.getX(ev, i);\n            final float y = MotionEventCompat.getY(ev, i);\n            mLastMotionX[pointerId] = x;\n            mLastMotionY[pointerId] = y;\n        }\n    }\n\n    /**\n     * Check if the given pointer ID represents a pointer that is currently down\n     * (to the best of the ViewDragHelper's knowledge).\n     * <p>\n     * The state used to report this information is populated by the methods\n     * {@link #shouldInterceptTouchEvent(MotionEvent)} or\n     * {@link #processTouchEvent(MotionEvent)}. If one of these\n     * methods has not been called for all relevant MotionEvents to track, the\n     * information reported by this method may be stale or incorrect.\n     * </p>\n     *\n     * @param pointerId pointer ID to check; corresponds to IDs provided by\n     *                  MotionEvent\n     * @return true if the pointer with the given ID is still down\n     */\n    public boolean isPointerDown(int pointerId) {\n        return (mPointersDown & 1 << pointerId) != 0;\n    }\n\n    void setDragState(int state) {\n        if (mDragState != state) {\n            mDragState = state;\n            mCallback.onViewDragStateChanged(state);\n            if (state == STATE_IDLE) {\n                mCapturedView = null;\n            }\n        }\n    }\n\n    /**\n     * Attempt to capture the view with the given pointer ID. The callback will\n     * be involved. This will put us into the \"dragging\" state. If we've already\n     * captured this view with this pointer this method will immediately return\n     * true without consulting the callback.\n     *\n     * @param toCapture View to capture\n     * @param pointerId Pointer to capture with\n     * @return true if capture was successful\n     */\n    boolean tryCaptureViewForDrag(View toCapture, int pointerId) {\n        if (toCapture == mCapturedView && mActivePointerId == pointerId) {\n            // Already done!\n            return true;\n        }\n        if (toCapture != null && mCallback.tryCaptureView(toCapture, pointerId)) {\n            mActivePointerId = pointerId;\n            captureChildView(toCapture, pointerId);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Tests scrollability within child views of v given a delta of dx.\n     *\n     * @param v      View to test for horizontal scrollability\n     * @param checkV Whether the view v passed should itself be checked for\n     *               scrollability (true), or just its children (false).\n     * @param dx     Delta scrolled in pixels along the X axis\n     * @param dy     Delta scrolled in pixels along the Y axis\n     * @param x      X coordinate of the active touch point\n     * @param y      Y coordinate of the active touch point\n     * @return true if child views of v can be scrolled by delta of dx.\n     */\n    protected boolean canScroll(View v, boolean checkV, int dx, int dy, int x, int y) {\n        if (v instanceof ViewGroup) {\n            final ViewGroup group = (ViewGroup) v;\n            final int scrollX = v.getScrollX();\n            final int scrollY = v.getScrollY();\n            final int count = group.getChildCount();\n            // Count backwards - let topmost views consume scroll distance\n            // first.\n            for (int i = count - 1; i >= 0; i--) {\n                // TODO: Add versioned support here for transformed views.\n                // This will not work for transformed views in Honeycomb+\n                final View child = group.getChildAt(i);\n                if (x + scrollX >= child.getLeft()\n                        && x + scrollX < child.getRight()\n                        && y + scrollY >= child.getTop()\n                        && y + scrollY < child.getBottom()\n                        && canScroll(child, true, dx, dy, x + scrollX - child.getLeft(), y\n                        + scrollY - child.getTop())) {\n                    return true;\n                }\n            }\n        }\n\n        return checkV\n                && (ViewCompat.canScrollHorizontally(v, -dx) || ViewCompat.canScrollVertically(v,\n                -dy));\n    }\n\n    /**\n     * Check if this event as provided to the parent view's\n     * onInterceptTouchEvent should cause the parent to intercept the touch\n     * event stream.\n     *\n     * @param ev MotionEvent provided to onInterceptTouchEvent\n     * @return true if the parent view should return true from\n     * onInterceptTouchEvent\n     */\n    public boolean shouldInterceptTouchEvent(MotionEvent ev) {\n        final int action = MotionEventCompat.getActionMasked(ev);\n        final int actionIndex = MotionEventCompat.getActionIndex(ev);\n\n        if (action == MotionEvent.ACTION_DOWN) {\n            // Reset things for a new event stream, just in case we didn't get\n            // the whole previous stream.\n            cancel();\n        }\n\n        if (mVelocityTracker == null) {\n            mVelocityTracker = VelocityTracker.obtain();\n        }\n        mVelocityTracker.addMovement(ev);\n\n        switch (action) {\n            case MotionEvent.ACTION_DOWN: {\n                final float x = ev.getX();\n                final float y = ev.getY();\n                final int pointerId = MotionEventCompat.getPointerId(ev, 0);\n                saveInitialMotion(x, y, pointerId);\n\n                final View toCapture = findTopChildUnder((int) x, (int) y);\n\n                // Catch a settling view if possible.\n                if (toCapture == mCapturedView && mDragState == STATE_SETTLING) {\n                    tryCaptureViewForDrag(toCapture, pointerId);\n                }\n\n                final int edgesTouched = mInitialEdgeTouched[pointerId];\n                if ((edgesTouched & mTrackingEdges) != 0) {\n                    mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);\n                }\n                break;\n            }\n\n            case MotionEventCompat.ACTION_POINTER_DOWN: {\n                final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);\n                final float x = MotionEventCompat.getX(ev, actionIndex);\n                final float y = MotionEventCompat.getY(ev, actionIndex);\n\n                saveInitialMotion(x, y, pointerId);\n\n                // A ViewDragHelper can only manipulate one view at a time.\n                if (mDragState == STATE_IDLE) {\n                    final int edgesTouched = mInitialEdgeTouched[pointerId];\n                    if ((edgesTouched & mTrackingEdges) != 0) {\n                        mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);\n                    }\n                } else if (mDragState == STATE_SETTLING) {\n                    // Catch a settling view if possible.\n                    final View toCapture = findTopChildUnder((int) x, (int) y);\n                    if (toCapture == mCapturedView) {\n                        tryCaptureViewForDrag(toCapture, pointerId);\n                    }\n                }\n                break;\n            }\n\n            case MotionEvent.ACTION_MOVE: {\n                // First to cross a touch slop over a draggable view wins. Also\n                // report edge drags.\n                final int pointerCount = MotionEventCompat.getPointerCount(ev);\n                for (int i = 0; i < pointerCount; i++) {\n                    final int pointerId = MotionEventCompat.getPointerId(ev, i);\n                    final float x = MotionEventCompat.getX(ev, i);\n                    final float y = MotionEventCompat.getY(ev, i);\n                    final float dx = x - mInitialMotionX[pointerId];\n                    final float dy = y - mInitialMotionY[pointerId];\n\n                    reportNewEdgeDrags(dx, dy, pointerId);\n                    if (mDragState == STATE_DRAGGING) {\n                        // Callback might have started an edge drag\n                        break;\n                    }\n\n                    final View toCapture = findTopChildUnder((int) x, (int) y);\n                    if (toCapture != null && checkTouchSlop(toCapture, dx, dy)\n                            && tryCaptureViewForDrag(toCapture, pointerId)) {\n                        break;\n                    }\n                }\n                saveLastMotion(ev);\n                break;\n            }\n\n            case MotionEventCompat.ACTION_POINTER_UP: {\n                final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);\n                clearMotionHistory(pointerId);\n                break;\n            }\n\n            case MotionEvent.ACTION_UP:\n            case MotionEvent.ACTION_CANCEL: {\n                cancel();\n                break;\n            }\n        }\n\n        return mDragState == STATE_DRAGGING;\n    }\n\n    /**\n     * Process a touch event received by the parent view. This method will\n     * dispatch callback events as needed before returning. The parent view's\n     * onTouchEvent implementation should call this.\n     *\n     * @param ev The touch event received by the parent view\n     */\n    public void processTouchEvent(MotionEvent ev) {\n        final int action = MotionEventCompat.getActionMasked(ev);\n        final int actionIndex = MotionEventCompat.getActionIndex(ev);\n\n        if (action == MotionEvent.ACTION_DOWN) {\n            // Reset things for a new event stream, just in case we didn't get\n            // the whole previous stream.\n            cancel();\n        }\n\n        if (mVelocityTracker == null) {\n            mVelocityTracker = VelocityTracker.obtain();\n        }\n        mVelocityTracker.addMovement(ev);\n\n        switch (action) {\n            case MotionEvent.ACTION_DOWN: {\n                final float x = ev.getX();\n                final float y = ev.getY();\n                final int pointerId = MotionEventCompat.getPointerId(ev, 0);\n                final View toCapture = findTopChildUnder((int) x, (int) y);\n\n                saveInitialMotion(x, y, pointerId);\n\n                // Since the parent is already directly processing this touch\n                // event,\n                // there is no reason to delay for a slop before dragging.\n                // Start immediately if possible.\n                tryCaptureViewForDrag(toCapture, pointerId);\n\n                final int edgesTouched = mInitialEdgeTouched[pointerId];\n                if ((edgesTouched & mTrackingEdges) != 0) {\n                    mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);\n                }\n                break;\n            }\n\n            case MotionEventCompat.ACTION_POINTER_DOWN: {\n                final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);\n                final float x = MotionEventCompat.getX(ev, actionIndex);\n                final float y = MotionEventCompat.getY(ev, actionIndex);\n\n                saveInitialMotion(x, y, pointerId);\n\n                // A ViewDragHelper can only manipulate one view at a time.\n                if (mDragState == STATE_IDLE) {\n                    // If we're idle we can do anything! Treat it like a normal\n                    // down event.\n\n                    final View toCapture = findTopChildUnder((int) x, (int) y);\n                    tryCaptureViewForDrag(toCapture, pointerId);\n\n                    final int edgesTouched = mInitialEdgeTouched[pointerId];\n                    if ((edgesTouched & mTrackingEdges) != 0) {\n                        mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);\n                    }\n                } else if (isCapturedViewUnder((int) x, (int) y)) {\n                    // We're still tracking a captured view. If the same view is\n                    // under this\n                    // point, we'll swap to controlling it with this pointer\n                    // instead.\n                    // (This will still work if we're \"catching\" a settling\n                    // view.)\n\n                    tryCaptureViewForDrag(mCapturedView, pointerId);\n                }\n                break;\n            }\n\n            case MotionEvent.ACTION_MOVE: {\n                if (mDragState == STATE_DRAGGING) {\n                    final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);\n                    if (index == -1) {\n                        Log.e(TAG, \"Invalid pointerId=\" + mActivePointerId + \" in onTouchEvent\");\n                        break;\n                    }\n                    final float x = MotionEventCompat.getX(ev, index);\n                    final float y = MotionEventCompat.getY(ev, index);\n                    final int idx = (int) (x - mLastMotionX[mActivePointerId]);\n                    final int idy = (int) (y - mLastMotionY[mActivePointerId]);\n\n                    dragTo(mCapturedView.getLeft() + idx, mCapturedView.getTop() + idy, idx, idy);\n\n                    saveLastMotion(ev);\n                } else {\n                    // Check to see if any pointer is now over a draggable view.\n                    final int pointerCount = MotionEventCompat.getPointerCount(ev);\n                    for (int i = 0; i < pointerCount; i++) {\n                        final int pointerId = MotionEventCompat.getPointerId(ev, i);\n                        final float x = MotionEventCompat.getX(ev, i);\n                        final float y = MotionEventCompat.getY(ev, i);\n                        final float dx = x - mInitialMotionX[pointerId];\n                        final float dy = y - mInitialMotionY[pointerId];\n\n                        reportNewEdgeDrags(dx, dy, pointerId);\n                        if (mDragState == STATE_DRAGGING) {\n                            // Callback might have started an edge drag.\n                            break;\n                        }\n\n                        final View toCapture = findTopChildUnder((int) x, (int) y);\n                        if (checkTouchSlop(toCapture, dx, dy)\n                                && tryCaptureViewForDrag(toCapture, pointerId)) {\n                            break;\n                        }\n                    }\n                    saveLastMotion(ev);\n                }\n                break;\n            }\n\n            case MotionEventCompat.ACTION_POINTER_UP: {\n                final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);\n                if (mDragState == STATE_DRAGGING && pointerId == mActivePointerId) {\n                    // Try to find another pointer that's still holding on to\n                    // the captured view.\n                    int newActivePointer = INVALID_POINTER;\n                    final int pointerCount = MotionEventCompat.getPointerCount(ev);\n                    for (int i = 0; i < pointerCount; i++) {\n                        final int id = MotionEventCompat.getPointerId(ev, i);\n                        if (id == mActivePointerId) {\n                            // This one's going away, skipActivity.\n                            continue;\n                        }\n\n                        final float x = MotionEventCompat.getX(ev, i);\n                        final float y = MotionEventCompat.getY(ev, i);\n                        if (findTopChildUnder((int) x, (int) y) == mCapturedView\n                                && tryCaptureViewForDrag(mCapturedView, id)) {\n                            newActivePointer = mActivePointerId;\n                            break;\n                        }\n                    }\n\n                    if (newActivePointer == INVALID_POINTER) {\n                        // We didn't find another pointer still touching the\n                        // view, release it.\n                        releaseViewForPointerUp();\n                    }\n                }\n                clearMotionHistory(pointerId);\n                break;\n            }\n\n            case MotionEvent.ACTION_UP: {\n                if (mDragState == STATE_DRAGGING) {\n                    releaseViewForPointerUp();\n                }\n                cancel();\n                break;\n            }\n\n            case MotionEvent.ACTION_CANCEL: {\n                if (mDragState == STATE_DRAGGING) {\n                    dispatchViewReleased(0, 0);\n                }\n                cancel();\n                break;\n            }\n        }\n    }\n\n    private void reportNewEdgeDrags(float dx, float dy, int pointerId) {\n        int dragsStarted = 0;\n        if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_LEFT)) {\n            dragsStarted |= EDGE_LEFT;\n        }\n        if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_TOP)) {\n            dragsStarted |= EDGE_TOP;\n        }\n        if (checkNewEdgeDrag(dx, dy, pointerId, EDGE_RIGHT)) {\n            dragsStarted |= EDGE_RIGHT;\n        }\n        if (checkNewEdgeDrag(dy, dx, pointerId, EDGE_BOTTOM)) {\n            dragsStarted |= EDGE_BOTTOM;\n        }\n\n        if (dragsStarted != 0) {\n            mEdgeDragsInProgress[pointerId] |= dragsStarted;\n            mCallback.onEdgeDragStarted(dragsStarted, pointerId);\n        }\n    }\n\n    private boolean checkNewEdgeDrag(float delta, float odelta, int pointerId, int edge) {\n        final float absDelta = Math.abs(delta);\n        final float absODelta = Math.abs(odelta);\n\n        if ((mInitialEdgeTouched[pointerId] & edge) != edge || (mTrackingEdges & edge) == 0\n                || (mEdgeDragsLocked[pointerId] & edge) == edge\n                || (mEdgeDragsInProgress[pointerId] & edge) == edge\n                || (absDelta <= mTouchSlop && absODelta <= mTouchSlop)) {\n            return false;\n        }\n        if (absDelta < absODelta * 0.5f && mCallback.onEdgeLock(edge)) {\n            mEdgeDragsLocked[pointerId] |= edge;\n            return false;\n        }\n        return (mEdgeDragsInProgress[pointerId] & edge) == 0 && absDelta > mTouchSlop;\n    }\n\n    /**\n     * Check if we've crossed a reasonable touch slop for the given child view.\n     * If the child cannot be dragged along the horizontal or vertical axis,\n     * motion along that axis will not count toward the slop check.\n     *\n     * @param child Child to check\n     * @param dx    Motion since initial position along X axis\n     * @param dy    Motion since initial position along Y axis\n     * @return true if the touch slop has been crossed\n     */\n    private boolean checkTouchSlop(View child, float dx, float dy) {\n        if (child == null) {\n            return false;\n        }\n        final boolean checkHorizontal = mCallback.getViewHorizontalDragRange(child) > 0;\n        final boolean checkVertical = mCallback.getViewVerticalDragRange(child) > 0;\n\n        if (checkHorizontal && checkVertical) {\n            return dx * dx + dy * dy > mTouchSlop * mTouchSlop;\n        } else if (checkHorizontal) {\n            return Math.abs(dx) > mTouchSlop;\n        } else if (checkVertical) {\n            return Math.abs(dy) > mTouchSlop;\n        }\n        return false;\n    }\n\n    /**\n     * Check if any pointer tracked in the current gesture has crossed the\n     * required slop threshold.\n     * <p>\n     * This depends on internal state populated by\n     * {@link #shouldInterceptTouchEvent(MotionEvent)} or\n     * {@link #processTouchEvent(MotionEvent)}. You should only\n     * rely on the results of this method after all currently available touch\n     * data has been provided to one of these two methods.\n     * </p>\n     *\n     * @param directions Combination of direction flags, see\n     *                   {@link #DIRECTION_HORIZONTAL}, {@link #DIRECTION_VERTICAL},\n     *                   {@link #DIRECTION_ALL}\n     * @return true if the slop threshold has been crossed, false otherwise\n     */\n    public boolean checkTouchSlop(int directions) {\n        final int count = mInitialMotionX.length;\n        for (int i = 0; i < count; i++) {\n            if (checkTouchSlop(directions, i)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Check if the specified pointer tracked in the current gesture has crossed\n     * the required slop threshold.\n     * <p>\n     * This depends on internal state populated by\n     * {@link #shouldInterceptTouchEvent(MotionEvent)} or\n     * {@link #processTouchEvent(MotionEvent)}. You should only\n     * rely on the results of this method after all currently available touch\n     * data has been provided to one of these two methods.\n     * </p>\n     *\n     * @param directions Combination of direction flags, see\n     *                   {@link #DIRECTION_HORIZONTAL}, {@link #DIRECTION_VERTICAL},\n     *                   {@link #DIRECTION_ALL}\n     * @param pointerId  ID of the pointer to slop check as specified by\n     *                   MotionEvent\n     * @return true if the slop threshold has been crossed, false otherwise\n     */\n    public boolean checkTouchSlop(int directions, int pointerId) {\n        if (!isPointerDown(pointerId)) {\n            return false;\n        }\n\n        final boolean checkHorizontal = (directions & DIRECTION_HORIZONTAL) == DIRECTION_HORIZONTAL;\n        final boolean checkVertical = (directions & DIRECTION_VERTICAL) == DIRECTION_VERTICAL;\n\n        final float dx = mLastMotionX[pointerId] - mInitialMotionX[pointerId];\n        final float dy = mLastMotionY[pointerId] - mInitialMotionY[pointerId];\n\n        if (checkHorizontal && checkVertical) {\n            return dx * dx + dy * dy > mTouchSlop * mTouchSlop;\n        } else if (checkHorizontal) {\n            return Math.abs(dx) > mTouchSlop;\n        } else if (checkVertical) {\n            return Math.abs(dy) > mTouchSlop;\n        }\n        return false;\n    }\n\n    /**\n     * Check if any of the edges specified were initially touched in the\n     * currently active gesture. If there is no currently active gesture this\n     * method will return false.\n     *\n     * @param edges Edges to check for an initial edge touch. See\n     *              {@link #EDGE_LEFT}, {@link #EDGE_TOP}, {@link #EDGE_RIGHT},\n     *              {@link #EDGE_BOTTOM} and {@link #EDGE_ALL}\n     * @return true if any of the edges specified were initially touched in the\n     * current gesture\n     */\n    public boolean isEdgeTouched(int edges) {\n        final int count = mInitialEdgeTouched.length;\n        for (int i = 0; i < count; i++) {\n            if (isEdgeTouched(edges, i)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Check if any of the edges specified were initially touched by the pointer\n     * with the specified ID. If there is no currently active gesture or if\n     * there is no pointer with the given ID currently down this method will\n     * return false.\n     *\n     * @param edges Edges to check for an initial edge touch. See\n     *              {@link #EDGE_LEFT}, {@link #EDGE_TOP}, {@link #EDGE_RIGHT},\n     *              {@link #EDGE_BOTTOM} and {@link #EDGE_ALL}\n     * @return true if any of the edges specified were initially touched in the\n     * current gesture\n     */\n    public boolean isEdgeTouched(int edges, int pointerId) {\n        return isPointerDown(pointerId) && (mInitialEdgeTouched[pointerId] & edges) != 0;\n    }\n\n    private void releaseViewForPointerUp() {\n        mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);\n        final float xvel = clampMag(\n                VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId),\n                mMinVelocity, mMaxVelocity);\n        final float yvel = clampMag(\n                VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId),\n                mMinVelocity, mMaxVelocity);\n        dispatchViewReleased(xvel, yvel);\n    }\n\n    private void dragTo(int left, int top, int dx, int dy) {\n        int clampedX = left;\n        int clampedY = top;\n        final int oldLeft = mCapturedView.getLeft();\n        final int oldTop = mCapturedView.getTop();\n        if (dx != 0) {\n            clampedX = mCallback.clampViewPositionHorizontal(mCapturedView, left, dx);\n            mCapturedView.offsetLeftAndRight(clampedX - oldLeft);\n        }\n        if (dy != 0) {\n            clampedY = mCallback.clampViewPositionVertical(mCapturedView, top, dy);\n            mCapturedView.offsetTopAndBottom(clampedY - oldTop);\n        }\n\n        if (dx != 0 || dy != 0) {\n            final int clampedDx = clampedX - oldLeft;\n            final int clampedDy = clampedY - oldTop;\n            mCallback\n                    .onViewPositionChanged(mCapturedView, clampedX, clampedY, clampedDx, clampedDy);\n        }\n    }\n\n    /**\n     * Determine if the currently captured view is under the given point in the\n     * parent view's coordinate system. If there is no captured view this method\n     * will return false.\n     *\n     * @param x X position to test in the parent's coordinate system\n     * @param y Y position to test in the parent's coordinate system\n     * @return true if the captured view is under the given point, false\n     * otherwise\n     */\n    public boolean isCapturedViewUnder(int x, int y) {\n        return isViewUnder(mCapturedView, x, y);\n    }\n\n    /**\n     * Determine if the supplied view is under the given point in the parent\n     * view's coordinate system.\n     *\n     * @param view Child view of the parent to hit test\n     * @param x    X position to test in the parent's coordinate system\n     * @param y    Y position to test in the parent's coordinate system\n     * @return true if the supplied view is under the given point, false\n     * otherwise\n     */\n    public boolean isViewUnder(View view, int x, int y) {\n        if (view == null) {\n            return false;\n        }\n        return x >= view.getLeft() && x < view.getRight() && y >= view.getTop()\n                && y < view.getBottom();\n    }\n\n    /**\n     * Find the topmost child under the given point within the parent view's\n     * coordinate system. The child order is determined using\n     * {@link ViewDragHelper.Callback#getOrderedChildIndex(int)}\n     * .\n     *\n     * @param x X position to test in the parent's coordinate system\n     * @param y Y position to test in the parent's coordinate system\n     * @return The topmost child view under (x, y) or null if none found.\n     */\n    public View findTopChildUnder(int x, int y) {\n        final int childCount = mParentView.getChildCount();\n        for (int i = childCount - 1; i >= 0; i--) {\n            final View child = mParentView.getChildAt(mCallback.getOrderedChildIndex(i));\n            if (x >= child.getLeft() && x < child.getRight() && y >= child.getTop()\n                    && y < child.getBottom()) {\n                return child;\n            }\n        }\n        return null;\n    }\n\n    private int getEdgeTouched(int x, int y) {\n        int result = 0;\n\n        if (x < mParentView.getLeft() + mEdgeSize)\n            result = EDGE_LEFT;\n        if (y < mParentView.getTop() + mEdgeSize)\n            result = EDGE_TOP;\n        if (x > mParentView.getRight() - mEdgeSize)\n            result = EDGE_RIGHT;\n        if (y > mParentView.getBottom() - mEdgeSize)\n            result = EDGE_BOTTOM;\n\n        return result;\n    }\n\n    /**\n     * A Callback is used as a communication channel with the ViewDragHelper\n     * back to the parent view using it. <code>on*</code>methods are invoked on\n     * siginficant events and several accessor methods are expected to provide\n     * the ViewDragHelper with more information about the state of the parent\n     * view upon request. The callback also makes decisions governing the range\n     * and draggability of child views.\n     */\n    public static abstract class Callback {\n        /**\n         * Called when the drag state changes. See the <code>STATE_*</code>\n         * constants for more information.\n         *\n         * @param state The new drag state\n         * @see #STATE_IDLE\n         * @see #STATE_DRAGGING\n         * @see #STATE_SETTLING\n         */\n        public void onViewDragStateChanged(int state) {\n        }\n\n        /**\n         * Called when the captured view's position changes as the result of a\n         * drag or settle.\n         *\n         * @param changedView View whose position changed\n         * @param left        New X coordinate of the left edge of the view\n         * @param top         New Y coordinate of the top edge of the view\n         * @param dx          Change in X position from the last call\n         * @param dy          Change in Y position from the last call\n         */\n        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {\n        }\n\n        /**\n         * Called when a child view is captured for dragging or settling. The ID\n         * of the pointer currently dragging the captured view is supplied. If\n         * activePointerId is identified as {@link #INVALID_POINTER} the capture\n         * is programmatic instead of pointer-initiated.\n         *\n         * @param capturedChild   Child view that was captured\n         * @param activePointerId Pointer id tracking the child capture\n         */\n        public void onViewCaptured(View capturedChild, int activePointerId) {\n        }\n\n        /**\n         * Called when the child view is no longer being actively dragged. The\n         * fling velocity is also supplied, if relevant. The velocity values may\n         * be clamped to system minimums or maximums.\n         * <p>\n         * Calling code may decide to fling or otherwise release the view to let\n         * it settle into place. It should do so using\n         * {@link #settleCapturedViewAt(int, int)} or\n         * {@link #flingCapturedView(int, int, int, int)}. If the Callback\n         * invokes one of these methods, the ViewDragHelper will enter\n         * {@link #STATE_SETTLING} and the view capture will not fully end until\n         * it comes to a complete stop. If neither of these methods is invoked\n         * before <code>onViewReleased</code> returns, the view will stop in\n         * place and the ViewDragHelper will return to {@link #STATE_IDLE}.\n         * </p>\n         *\n         * @param releasedChild The captured child view now being released\n         * @param xvel          X velocity of the pointer as it left the screen in pixels\n         *                      per second.\n         * @param yvel          Y velocity of the pointer as it left the screen in pixels\n         *                      per second.\n         */\n        public void onViewReleased(View releasedChild, float xvel, float yvel) {\n        }\n\n        /**\n         * Called when one of the subscribed edges in the parent view has been\n         * touched by the user while no child view is currently captured.\n         *\n         * @param edgeFlags A combination of edge flags describing the edge(s)\n         *                  currently touched\n         * @param pointerId ID of the pointer touching the described edge(s)\n         * @see #EDGE_LEFT\n         * @see #EDGE_TOP\n         * @see #EDGE_RIGHT\n         * @see #EDGE_BOTTOM\n         */\n        public void onEdgeTouched(int edgeFlags, int pointerId) {\n        }\n\n        /**\n         * Called when the given edge may become locked. This can happen if an\n         * edge drag was preliminarily rejected before beginning, but after\n         * {@link #onEdgeTouched(int, int)} was called. This method should\n         * return true to lock this edge or false to leave it unlocked. The\n         * default behavior is to leave edges unlocked.\n         *\n         * @param edgeFlags A combination of edge flags describing the edge(s)\n         *                  locked\n         * @return true to lock the edge, false to leave it unlocked\n         */\n        public boolean onEdgeLock(int edgeFlags) {\n            return false;\n        }\n\n        /**\n         * Called when the user has started a deliberate drag away from one of\n         * the subscribed edges in the parent view while no child view is\n         * currently captured.\n         *\n         * @param edgeFlags A combination of edge flags describing the edge(s)\n         *                  dragged\n         * @param pointerId ID of the pointer touching the described edge(s)\n         * @see #EDGE_LEFT\n         * @see #EDGE_TOP\n         * @see #EDGE_RIGHT\n         * @see #EDGE_BOTTOM\n         */\n        public void onEdgeDragStarted(int edgeFlags, int pointerId) {\n        }\n\n        /**\n         * Called to determine the Z-order of child views.\n         *\n         * @param index the ordered position to query for\n         * @return index of the view that should be ordered at position\n         * <code>index</code>\n         */\n        public int getOrderedChildIndex(int index) {\n            return index;\n        }\n\n        /**\n         * Return the magnitude of a draggable child view's horizontal range of\n         * motion in pixels. This method should return 0 for views that cannot\n         * move horizontally.\n         *\n         * @param child Child view to check\n         * @return range of horizontal motion in pixels\n         */\n        public int getViewHorizontalDragRange(View child) {\n            return 0;\n        }\n\n        /**\n         * Return the magnitude of a draggable child view's vertical range of\n         * motion in pixels. This method should return 0 for views that cannot\n         * move vertically.\n         *\n         * @param child Child view to check\n         * @return range of vertical motion in pixels\n         */\n        public int getViewVerticalDragRange(View child) {\n            return 0;\n        }\n\n        /**\n         * Called when the user's input indicates that they want to capture the\n         * given child view with the pointer indicated by pointerId. The\n         * callback should return true if the user is permitted to drag the\n         * given view with the indicated pointer.\n         * <p>\n         * ViewDragHelper may call this method multiple times for the same view\n         * even if the view is already captured; this indicates that a new\n         * pointer is trying to take control of the view.\n         * </p>\n         * <p>\n         * If this method returns true, a call to\n         * {@link #onViewCaptured(View, int)} will follow if the\n         * capture is successful.\n         * </p>\n         *\n         * @param child     Child the user is attempting to capture\n         * @param pointerId ID of the pointer attempting the capture\n         * @return true if capture should be allowed, false otherwise\n         */\n        public abstract boolean tryCaptureView(View child, int pointerId);\n\n        /**\n         * Restrict the motion of the dragged child view along the horizontal\n         * axis. The default implementation does not allow horizontal motion;\n         * the extending class must override this method and provide the desired\n         * clamping.\n         *\n         * @param child Child view being dragged\n         * @param left  Attempted motion along the X axis\n         * @param dx    Proposed change in position for left\n         * @return The new clamped position for left\n         */\n        public int clampViewPositionHorizontal(View child, int left, int dx) {\n            return 0;\n        }\n\n        /**\n         * Restrict the motion of the dragged child view along the vertical\n         * axis. The default implementation does not allow vertical motion; the\n         * extending class must override this method and provide the desired\n         * clamping.\n         *\n         * @param child Child view being dragged\n         * @param top   Attempted motion along the Y axis\n         * @param dy    Proposed change in position for top\n         * @return The new clamped position for top\n         */\n        public int clampViewPositionVertical(View child, int top, int dy) {\n            return 0;\n        }\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/swipebacklayout/app/SwipeBackActivity.java",
    "content": "package androlua.widget.swipebacklayout.app;\n\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.view.View;\n\nimport androlua.widget.swipebacklayout.SwipeBackLayout;\nimport androlua.widget.swipebacklayout.Utils;\n\n\npublic class SwipeBackActivity extends AppCompatActivity implements SwipeBackActivityBase {\n\n    private SwipeBackActivityHelper mHelper;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mHelper = new SwipeBackActivityHelper(this);\n        mHelper.onActivityCreate();\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n\n    }\n\n    @Override\n    protected void onPostCreate(Bundle savedInstanceState) {\n        super.onPostCreate(savedInstanceState);\n        if (needPostCreate()) {\n            mHelper.onPostCreate();\n        }\n    }\n\n    @Override\n    public View findViewById(int id) {\n        View v = super.findViewById(id);\n        if (v == null && mHelper != null)\n            return mHelper.findViewById(id);\n        return v;\n    }\n\n    @Override\n    public SwipeBackLayout getSwipeBackLayout() {\n        return mHelper.getSwipeBackLayout();\n    }\n\n    @Override\n    public void setSwipeBackEnable(boolean enable) {\n        getSwipeBackLayout().setEnableGesture(enable);\n    }\n\n    @Override\n    public void scrollToFinishActivity() {\n        Utils.convertActivityToTranslucent(this);\n        getSwipeBackLayout().scrollToFinishActivity();\n    }\n\n    protected boolean needPostCreate() {\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/swipebacklayout/app/SwipeBackActivityBase.java",
    "content": "package androlua.widget.swipebacklayout.app;\n\n\nimport androlua.widget.swipebacklayout.SwipeBackLayout;\n\n/**\n * @author Yrom\n */\npublic interface SwipeBackActivityBase {\n    /**\n     * @return the SwipeBackLayout associated with this activity.\n     */\n    public abstract SwipeBackLayout getSwipeBackLayout();\n\n    public abstract void setSwipeBackEnable(boolean enable);\n\n    /**\n     * Scroll out contentView and finish the activity\n     */\n    public abstract void scrollToFinishActivity();\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/swipebacklayout/app/SwipeBackActivityHelper.java",
    "content": "package androlua.widget.swipebacklayout.app;\n\nimport android.app.Activity;\nimport android.graphics.Color;\nimport android.graphics.drawable.ColorDrawable;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androlua.widget.swipebacklayout.SwipeBackLayout;\nimport androlua.widget.swipebacklayout.Utils;\n\n\n/**\n * @author Yrom\n */\npublic class SwipeBackActivityHelper {\n    private Activity mActivity;\n\n    private SwipeBackLayout mSwipeBackLayout;\n\n    public SwipeBackActivityHelper(Activity activity) {\n        mActivity = activity;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public void onActivityCreate() {\n        mActivity.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));\n        mActivity.getWindow().getDecorView().setBackgroundDrawable(null);\n        mSwipeBackLayout = new SwipeBackLayout(mActivity);\n        mSwipeBackLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));\n        mSwipeBackLayout.addSwipeListener(new SwipeBackLayout.SwipeListener() {\n            @Override\n            public void onScrollStateChange(int state, float scrollPercent) {\n            }\n\n            @Override\n            public void onEdgeTouch(int edgeFlag) {\n                Utils.convertActivityToTranslucent(mActivity);\n            }\n\n            @Override\n            public void onScrollOverThreshold() {\n\n            }\n        });\n    }\n\n    public void onPostCreate() {\n        mSwipeBackLayout.attachToActivity(mActivity);\n    }\n\n    public View findViewById(int id) {\n        if (mSwipeBackLayout != null) {\n            return mSwipeBackLayout.findViewById(id);\n        }\n        return null;\n    }\n\n    public SwipeBackLayout getSwipeBackLayout() {\n        return mSwipeBackLayout;\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/swipebacklayout/app/SwipeBackPreferenceActivity.java",
    "content": "package androlua.widget.swipebacklayout.app;\n\nimport android.os.Bundle;\nimport android.preference.PreferenceActivity;\nimport android.view.View;\n\nimport androlua.widget.swipebacklayout.SwipeBackLayout;\n\n\npublic class SwipeBackPreferenceActivity extends PreferenceActivity implements SwipeBackActivityBase {\n    private SwipeBackActivityHelper mHelper;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mHelper = new SwipeBackActivityHelper(this);\n        mHelper.onActivityCreate();\n    }\n\n    @Override\n    protected void onPostCreate(Bundle savedInstanceState) {\n        super.onPostCreate(savedInstanceState);\n        mHelper.onPostCreate();\n    }\n\n    @Override\n    public View findViewById(int id) {\n        View v = super.findViewById(id);\n        if (v == null && mHelper != null)\n            return mHelper.findViewById(id);\n        return v;\n    }\n\n    @Override\n    public SwipeBackLayout getSwipeBackLayout() {\n        return mHelper.getSwipeBackLayout();\n    }\n\n    @Override\n    public void setSwipeBackEnable(boolean enable) {\n        getSwipeBackLayout().setEnableGesture(enable);\n    }\n\n    @Override\n    public void scrollToFinishActivity() {\n        getSwipeBackLayout().scrollToFinishActivity();\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/video/VideoPlayerActivity.java",
    "content": "package androlua.widget.video;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.view.View;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport androlua.LuaImageLoader;\nimport androlua.base.BaseActivity;\nimport cn.jzvd.JZVideoPlayer;\nimport cn.jzvd.JZVideoPlayerStandard;\nimport pub.hanks.luajandroid.R;\n\n/**\n * Created by hanks on 2017/6/2. Copyright (C) 2017 Hanks\n */\n\npublic class VideoPlayerActivity extends BaseActivity {\n\n    public static void start(Context context, String json) {\n        Intent starter = new Intent(context, VideoPlayerActivity.class);\n        starter.putExtra(\"json\", json);\n        context.startActivity(starter);\n    }\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_video);\n        this.getWindow().getDecorView().setBackgroundColor(Color.TRANSPARENT);\n        JZVideoPlayerStandard videoplayer = (JZVideoPlayerStandard) findViewById(R.id.videoplayer);\n        try {\n            String extra = getIntent().getStringExtra(\"json\");\n            JSONObject json = new JSONObject(extra);\n            String url = json.getString(\"url\");\n            String poster = \"\";\n            if (json.has(\"poster\")) {\n                poster = json.getString(\"poster\");\n            }\n            LuaImageLoader.load(videoplayer.thumbImageView, poster);\n            videoplayer.setAllControlsVisiblity(0, 0, 0, 0, 0, View.INVISIBLE, View.INVISIBLE);\n            videoplayer.setUp(url, JZVideoPlayer.SCREEN_WINDOW_LIST, \"\");\n//            JZVideoPlayerStandard.startFullscreen(this, JZVideoPlayerStandard.class, url, \"\");\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onBackPressed() {\n        if (JZVideoPlayer.backPress()) {\n            return;\n        }\n        super.onBackPressed();\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        JZVideoPlayer.releaseAllVideos();\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/viewpager/NoScrollViewPager.java",
    "content": "package androlua.widget.viewpager;\n\nimport android.content.Context;\nimport android.support.v4.view.ViewPager;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.View;\n\n\n/**\n * 可以禁止左右滑动\n * Created by hanks on 16/7/18.\n */\npublic class NoScrollViewPager extends ViewPager {\n\n    private boolean isPagingEnabled = false;\n\n    public NoScrollViewPager(Context context) {\n        super(context);\n    }\n\n    public NoScrollViewPager(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent event) {\n        return this.isPagingEnabled && super.onTouchEvent(event);\n    }\n\n    @Override\n    public boolean onInterceptTouchEvent(MotionEvent event) {\n        return this.isPagingEnabled && super.onInterceptTouchEvent(event);\n    }\n\n\n    @Override\n    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {\n        if (v != this && v instanceof ViewPager) {\n\n            int currentItem = ((ViewPager) v).getCurrentItem();\n            int countItem = ((ViewPager) v).getAdapter().getCount();\n            return !((currentItem == (countItem - 1) && dx < 0) || (currentItem == 0 && dx > 0));\n        }\n        return super.canScroll(v, checkV, dx, x, y);\n    }\n\n    public void setPagingEnabled(boolean b) {\n        this.isPagingEnabled = b;\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/androlua/widget/webview/WebViewActivity.java",
    "content": "package androlua.widget.webview;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.support.annotation.ColorInt;\nimport android.support.annotation.Nullable;\nimport android.support.v4.view.GravityCompat;\nimport android.support.v7.widget.PopupMenu;\nimport android.text.TextUtils;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.webkit.WebChromeClient;\nimport android.webkit.WebResourceRequest;\nimport android.webkit.WebSettings;\nimport android.webkit.WebView;\nimport android.webkit.WebViewClient;\nimport android.widget.EditText;\nimport android.widget.TextView;\n\nimport androlua.LuaUtil;\nimport androlua.base.BaseActivity;\nimport androlua.widget.statusbar.StatusBarView;\nimport pub.hanks.luajandroid.R;\n\n/**\n * Created by hanks on 2017/6/2. Copyright (C) 2017 Hanks\n */\n\npublic class WebViewActivity extends BaseActivity {\n\n    private EditText etUrl;\n    private String url, webTitle;\n    private int color;\n    private WebView mWebView;\n    private View loading;\n    private View layout_toolbar;\n    private View ivRefresh, iv_more;\n    private Bitmap colorBitmap;\n    private Canvas canvas;\n    private StatusBarView view_statusbar;\n\n    public static void start(Context context, String url) {\n        start(context, url, Color.TRANSPARENT);\n    }\n\n    public static void start(Context context, String url, int color) {\n        Intent starter = new Intent(context, WebViewActivity.class);\n        starter.putExtra(\"url\", url);\n        starter.putExtra(\"color\", color);\n        context.startActivity(starter);\n    }\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_webview);\n        etUrl = (EditText) findViewById(R.id.et_url);\n        loading = findViewById(R.id.loading);\n        layout_toolbar = findViewById(R.id.layout_toolbar);\n        mWebView = (WebView) findViewById(R.id.webview);\n        ivRefresh = findViewById(R.id.iv_refresh);\n        iv_more = findViewById(R.id.iv_more);\n        view_statusbar = (StatusBarView) findViewById(R.id.view_statusbar);\n        colorBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);\n        canvas = new Canvas(colorBitmap);\n\n        WebSettings settings = mWebView.getSettings();\n        settings.setUseWideViewPort(true);\n        settings.setAppCacheEnabled(true);\n        settings.setJavaScriptCanOpenWindowsAutomatically(true);\n        settings.setDisplayZoomControls(false);\n        settings.setSupportMultipleWindows(true);\n        settings.setJavaScriptEnabled(true);\n        settings.setDomStorageEnabled(true);\n        settings.setAllowContentAccess(true);\n        settings.setDatabaseEnabled(true);\n\n        if (Build.VERSION.SDK_INT >= 19) {\n            mWebView.setWebContentsDebuggingEnabled(true);\n        }\n\n        url = getIntent().getStringExtra(\"url\");\n        color = getIntent().getIntExtra(\"color\", 0);\n        if (color == Color.TRANSPARENT) {\n            setLightStatusBar();\n        } else {\n            setStatusBarColor(color);\n            layout_toolbar.setBackgroundColor(color);\n        }\n        etUrl.setText(url);\n        etUrl.setOnFocusChangeListener(new View.OnFocusChangeListener() {\n            @Override\n            public void onFocusChange(View v, boolean hasFocus) {\n                if (TextUtils.isEmpty(url) || TextUtils.isEmpty(webTitle)) {\n                    return;\n                }\n                if (hasFocus) {\n                    etUrl.setText(url);\n                } else {\n                    etUrl.setText(webTitle);\n                }\n            }\n        });\n        mWebView.setWebChromeClient(new WebChromeClient() {\n            @Override\n            public void onProgressChanged(WebView view, int newProgress) {\n                super.onProgressChanged(view, newProgress);\n            }\n\n            @Override\n            public void onReceivedTitle(WebView view, String title) {\n                super.onReceivedTitle(view, title);\n                webTitle = title;\n                etUrl.setText(title);\n            }\n\n        });\n        mWebView.setWebViewClient(new WebViewClient() {\n            @Override\n            public void onPageStarted(WebView view, String url, Bitmap favicon) {\n                super.onPageStarted(view, url, favicon);\n                loading.setVisibility(View.VISIBLE);\n                ivRefresh.setVisibility(View.GONE);\n            }\n\n            @Override\n            public void onPageFinished(WebView view, String url) {\n                super.onPageFinished(view, url);\n                loading.setVisibility(View.GONE);\n                ivRefresh.setVisibility(View.VISIBLE);\n                fetchColor();\n            }\n\n            @Deprecated\n            public boolean shouldOverrideUrlLoading(WebView view, String url) {\n                return !url.startsWith(\"http://\") && !url.startsWith(\"https://\") && !url.startsWith(\"hydrogen://\");\n            }\n\n            @Override\n            public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest webResourceRequest) {\n                String url = \"\";\n                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {\n                    url = webResourceRequest.getUrl().toString();\n                }\n                return !url.startsWith(\"http://\") && !url.startsWith(\"https://\") && !url.startsWith(\"hydrogen://\");\n            }\n        });\n\n        ivRefresh.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                mWebView.loadUrl(url);\n            }\n        });\n\n        mWebView.loadUrl(url);\n\n        iv_more.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                PopupMenu popupMenu = new PopupMenu(iv_more.getContext(), v, GravityCompat.START);\n                popupMenu.getMenu().add(Menu.NONE, 1, Menu.NONE, \"复制链接\");\n                popupMenu.getMenu().add(Menu.NONE, 2, Menu.NONE, \"在浏览器打开\");\n                popupMenu.getMenu().add(Menu.NONE, 3, Menu.NONE, \"分享\");\n                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {\n                    @Override\n                    public boolean onMenuItemClick(MenuItem item) {\n                        if (TextUtils.isEmpty(url)) {\n                            return false;\n                        }\n                        switch (item.getItemId()) {\n                            case 1:\n                                android.content.ClipboardManager clipboard = (android.content.ClipboardManager) WebViewActivity.this.getSystemService(Context.CLIPBOARD_SERVICE);\n                                android.content.ClipData clip = android.content.ClipData.newPlainText(\"lua\", url);\n                                clipboard.setPrimaryClip(clip);\n                                break;\n                            case 2:\n                                Intent intent = new Intent(Intent.ACTION_VIEW);\n                                intent.setData(Uri.parse(url));\n                                WebViewActivity.this.startActivity(intent);\n                                break;\n                            case 3:\n                                Intent sendIntent = new Intent(Intent.ACTION_SEND);\n                                sendIntent.putExtra(Intent.EXTRA_TEXT, url);\n                                sendIntent.setType(\"text/plain\");\n                                WebViewActivity.this.startActivity(sendIntent);\n                                break;\n                        }\n                        return false;\n                    }\n                });\n                popupMenu.show();\n            }\n        });\n        etUrl.setOnEditorActionListener(new TextView.OnEditorActionListener() {\n            @Override\n            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {\n                String url = etUrl.getText().toString();\n                if (!TextUtils.isEmpty(url) && url.startsWith(\"http\")) {\n                    mWebView.loadUrl(url);\n                }\n                return false;\n            }\n        });\n\n    }\n\n    private boolean canAsBgColor(int i) {\n        return Color.red(i) < 220 || Color.green(i) < 220 || Color.blue(i) < 220;\n    }\n\n    private void fetchColor() {\n        if (mWebView != null && mWebView.getVisibility() == View.VISIBLE && mWebView.getScrollX() < LuaUtil.dp2px(20)) {\n            mWebView.draw(canvas);\n            if (colorBitmap != null) {\n                int pixel = colorBitmap.getPixel(0, 0);\n                if (canAsBgColor(pixel)) {\n                    layout_toolbar.setBackgroundColor(pixel);\n                    if (pixel == Color.WHITE) {\n                        setLightStatusBar();\n                    } else {\n                        setStatusBarColor(pixel);\n                    }\n                }\n            }\n        }\n    }\n\n    @Override\n    public void onBackPressed() {\n        if (mWebView.canGoBack()) {\n            mWebView.goBack();\n            return;\n        }\n        super.onBackPressed();\n\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        try {\n            if (mWebView != null) {\n                if (mWebView.getParent() instanceof ViewGroup) {\n                    ((ViewGroup) mWebView.getParent()).removeAllViews();\n                }\n                mWebView.stopLoading();\n                mWebView.setWebChromeClient(null);\n                mWebView.setWebViewClient(null);\n                mWebView.removeAllViews();\n                mWebView.destroy();\n                mWebView = null;\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/Console.java",
    "content": "package com.luajava;\n\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\n\npublic class Console {\n    public static void main(String[] args) {\n        try {\n            LuaState L = LuaStateFactory.newLuaState();\n            L.openLibs();\n            if (args.length > 0) {\n                for (int i = 0; i < args.length; i++) {\n                    int res = L.LloadFile(args[i]);\n                    if (res == 0) {\n                        res = L.pcall(0, 0, 0);\n                    }\n                    if (res != 0) {\n                        throw new LuaException(\"Error on file: \" + args[i] + \". \" + L.toString(-1));\n                    }\n                }\n                return;\n            }\n            System.out.println(\"API Lua Java - console mode.\");\n            BufferedReader inp = new BufferedReader(new InputStreamReader(System.in));\n            System.out.print(\"> \");\n            while (true) {\n                String line = inp.readLine();\n                if (line == null || line.equals(\"exit\")) {\n                    L.close();\n                } else {\n                    int ret = L.LloadBuffer(line.getBytes(), \"from console\");\n                    if (ret == 0) {\n                        ret = L.pcall(0, 0, 0);\n                    }\n                    if (ret != 0) {\n                        System.err.println(\"Error on line: \" + line);\n                        System.err.println(L.toString(-1));\n                    }\n                    System.out.print(\"> \");\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/JavaFunction.java",
    "content": "package com.luajava;\n\npublic abstract class JavaFunction {\n    protected LuaState L;\n\n    public JavaFunction(LuaState L) {\n        this.L = L;\n    }\n\n    public abstract int execute() throws LuaException;\n\n    public LuaObject getParam(int idx) {\n        return this.L.getLuaObject(idx);\n    }\n\n    public void register(String name) throws LuaException {\n        synchronized (this.L) {\n            this.L.pushJavaFunction(this);\n            this.L.setGlobal(name);\n        }\n    }\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/LuaException.java",
    "content": "/*\n * $Id: LuaException.java,v 1.6 2006/12/22 14:06:40 thiago Exp $\n * Copyright (C) 2003-2007 Kepler Project.\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\npackage com.luajava;\n\n/**\n * LuaJava exception\n *\n * @author Thiago Ponte\n */\npublic class LuaException extends Exception {\n    /**\n     *\n     */\n    private static final long serialVersionUID = 1L;\n\n    public LuaException(String str) {\n        super(str);\n    }\n\n    /**\n     * Will work only on Java 1.4 or later.\n     * To work with Java 1.3, comment the first line and uncomment the second one.\n     */\n    public LuaException(Exception e) {\n        super((e.getCause() != null) ? e.getCause() : e);\n        //super(e.getMessage());\n    }\n} \n"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/LuaFunction.java",
    "content": "package com.luajava;\n\npublic class LuaFunction<T extends Object> extends LuaObject implements LuaMetaTable {\n\n    protected LuaFunction(LuaState L, String globalName) {\n        super(L, globalName);\n    }\n\n    protected LuaFunction(LuaState L, int index) {\n        super(L, index);\n    }\n\n    @Override\n    public T __call(Object[] arg) throws LuaException {\n        // TODO: Implement this method\n        return (T) super.call(arg);\n    }\n\n    @Override\n    public Object __index(String key) {\n        // TODO: Implement this method\n        return null;\n    }\n\n    @Override\n    public void __newIndex(String key, Object value) {\n        // TODO: Implement this method\n    }\n\n    @Override\n    public T call(Object... args) throws LuaException {\n        // TODO: Implement this method\n        return (T) super.call(args);\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/LuaInvocationHandler.java",
    "content": "/*\n * $Id: LuaInvocationHandler.java,v 1.4 2006/12/22 14:06:40 thiago Exp $\n * Copyright (C) 2003-2007 Kepler Project.\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\npackage com.luajava;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\n\n/**\n * Class that implements the InvocationHandler interface.\n * This class is used in the LuaJava's proxy system.\n * When a proxy object is accessed, the method invoked is\n * called from Lua\n *\n * @author Rizzato\n * @author Thiago Ponte\n */\npublic class LuaInvocationHandler implements InvocationHandler {\n    private LuaObject obj;\n\n    private LuaState L;\n\n    private LuaObject print;\n\n\n    public LuaInvocationHandler(LuaObject obj) {\n        this.obj = obj;\n        L = obj.L;\n        print = L.getLuaObject(\"print\");\n    }\n\n    /**\n     * Function called when a proxy object function is invoked.\n     */\n    public Object invoke(Object proxy, Method method, Object[] args) throws LuaException {\n        synchronized (obj.L) {\n            String methodName = method.getName();\n            LuaObject func = obj.getField(methodName);\n            Class<?> retType = method.getReturnType();\n\n            if (func.isNil()) {\n                if (retType.equals(boolean.class) || retType.equals(Boolean.class))\n                    return false;\n                else if (retType.isPrimitive() || Number.class.isAssignableFrom(retType))\n                    return 0;\n                else\n                    return null;\n            }\n\n            Object ret = null;\n            try {\n                // Checks if returned type is void. if it is returns null.\n                if (retType.equals(Void.class) || retType.equals(void.class)) {\n                    func.call(args);\n                    ret = null;\n                } else {\n                    ret = func.call(args);\n                    if (ret != null && ret instanceof Double) {\n                        ret = LuaState.convertLuaNumber((Double) ret, retType);\n                    }\n                }\n            } catch (LuaException e) {\n                print.call(methodName + \" \" + e.getMessage());\n            }\n            if (ret == null)\n                if (retType.equals(boolean.class) || retType.equals(Boolean.class))\n                    return false;\n                else if (retType.isPrimitive() || Number.class.isAssignableFrom(retType))\n                    return 0;\n            return ret;\n        }\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/LuaJavaAPI.java",
    "content": "/*\n * $Id: LuaJavaAPI.java,v 1.4 2006/12/22 14:06:40 thiago Exp $\n * Copyright (C) 2003-2007 Kepler Project.\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Softwarea.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\npackage com.luajava;\n\nimport android.util.Log;\n\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Class that contains functions accessed by lua.\n *\n * @author Thiago Ponte\n */\npublic final class LuaJavaAPI {\n    public static HashMap<String, Method[]> methodsMap = new HashMap<String, Method[]>();\n    public static HashMap<String, Method[]> methodCache = new HashMap<String, Method[]>();\n\n    private static Class<?> LuaState_class = LuaState.class;\n\n    private static Class<?> String_class = String.class;\n\n    private static Class<?> List_class = List.class;\n\n    private static Class<?> ArrayList_class = ArrayList.class;\n\n    private static Class<?> HashMap_class = HashMap.class;\n\n    private static Class<?> Map_class = Map.class;\n\n    private static Class<?> LuaFunction_class = LuaFunction.class;\n\n    private static Class<?> LuaObject_class = LuaObject.class;\n\n    private static Class<?> LuaTable_class = LuaTable.class;\n\n    private static Class<?> Number_class = Number.class;\n\n    private static Class<?> Character_class = Character.class;\n\n    private LuaJavaAPI() {\n    }\n\n    /**\n     * Java implementation of the metamethod __index\n     *\n     * @param luaState   int that indicates the state used\n     * @param obj        Object to be indexed\n     * @param methodName the name of the method\n     * @return number of returned objects\n     */\n\n    public static int objectIndex(long luaState, Object obj, String searchName, int type)\n            throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n        synchronized (L) {\n\n            int ret = 0;\n            if (type == 0)\n                if (checkMethod(L, obj, searchName) != 0)\n                    return 2;\n\n            if (type == 0 || type == 1 || type == 5)\n                if ((ret = checkField(L, obj, searchName)) != 0)\n                    return ret;\n\n            if (type == 0 || type == 4)\n                if (javaGetter(L, obj, searchName) != 0)\n                    return 4;\n\n            if (type == 0 || type == 3)\n                if (checkClass(L, obj, searchName) != 0)\n                    return 3;\n\n            if ((type == 0 || type == 6) && obj instanceof LuaMetaTable) {\n                Object res = ((LuaMetaTable) obj).__index(searchName);\n                L.pushObjectValue(res);\n                return 6;\n            }\n\n            return 0;\n        }\n    }\n\n    public static int callMethod(long luaState, Object obj, String cacheName)\n            throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n\n        synchronized (L) {\n            Method[] methods = methodCache.get(cacheName);\n            int top = L.getTop();\n            Object[] objs = new Object[top];\n            Method method = null;\n            // gets method and arguments\n            for (int i = 0; i < methods.length; i++) {\n\n                Class[] parameters = methods[i].getParameterTypes();\n                if (parameters.length != top)\n                    continue;\n\n                boolean okMethod = true;\n\n                for (int j = 0; j < parameters.length; j++) {\n                    try {\n                        objs[j] = compareTypes(L, parameters[j], j + 1);\n\n                    } catch (Exception e) {\n                        okMethod = false;\n                        break;\n                    }\n                }\n\n                if (okMethod) {\n                    method = methods[i];\n                    break;\n                }\n\n            }\n\n            // If method is null means there isn't one receiving the given arguments\n            if (method == null) {\n                StringBuilder msgbuilder = new StringBuilder();\n                for (int i = 0; i < methods.length; i++) {\n                    msgbuilder.append(methods[i].toString());\n                    msgbuilder.append(\"\\n\");\n                }\n                throw new LuaException(\"Invalid method call. Invalid Parameters.\\n\" + msgbuilder.toString());\n            }\n\n            Object ret;\n            try {\n                if (!Modifier.isPublic(method.getModifiers()))\n                    method.setAccessible(true);\n\n                ret = method.invoke(obj, objs);\n            } catch (Exception e) {\n                throw new LuaException(e);\n            }\n\n            // Void function returns null\n            if (ret == null && method.getReturnType().equals(Void.TYPE))\n                return 0;\n\n            // push result\n            L.pushObjectValue(ret);\n\n            return 1;\n        }\n    }\n\n\n    /**\n     * Java implementation of the metamethod __newindex\n     *\n     * @param luaState   int that indicates the state used\n     * @param obj        Object to be indexed\n     * @param searchName the name of the method\n     * @return number of returned objects\n     */\n\n    public static int objectNewIndex(long luaState, Object obj, String searchName)\n            throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n        synchronized (L) {\n            int res;\n\n            res = setFieldValue(L, obj, searchName);\n            if (res != 0)\n                return 1;\n\n            res = javaSetter(L, obj, searchName);\n            if (res != 0)\n                return 1;\n\n            return 0;\n        }\n    }\n\n\n    public static int setFieldValue(LuaState L, Object obj, String fieldName) throws LuaException {\n        synchronized (L) {\n            Field field = null;\n            Class objClass;\n            boolean isClass = false;\n\n            if (obj == null)\n                return 0;\n\n            if (obj instanceof Class) {\n                objClass = (Class) obj;\n                isClass = true;\n            } else {\n                objClass = obj.getClass();\n            }\n\n            try {\n                field = objClass.getField(fieldName);\n            } catch (NoSuchFieldException e) {\n                /*try\n                 {\n\t\t\t\t field = objClass.getDeclaredField(fieldName);\n\t\t\t\t }\n\t\t\t\t catch (Exception e2)\n\t\t\t\t */\n                {\n                    return 0;\n                }\n            }\n\n            if (field == null)\n                return 0;\n            if (isClass && !Modifier.isStatic(field.getModifiers()))\n                return 0;\n            Class type = field.getType();\n            try {\n                if (!Modifier.isPublic(field.getModifiers()))\n                    field.setAccessible(true);\n\n                field.set(obj, compareTypes(L, type, 3));\n            } catch (LuaException e) {\n                argError(L, fieldName, 3, type);\n            } catch (Exception e) {\n                throw new LuaException(e);\n            }\n\n            return 1;\n        }\n    }\n\n    private static String argError(LuaState L, String name, int idx, Class type) throws LuaException {\n\n        throw new LuaException(\"bad argument to '\" + name + \"' (\" + type.getName() + \" expected, got \" + typeName(L, 3) + \" value)\");\n\n    }\n\n    private static String typeName(LuaState L, int idx) throws LuaException {\n        if (L.isObject(idx)) {\n            return L.getObjectFromUserdata(idx).getClass().getName();\n        }\n        switch (L.type(idx)) {\n            case LuaState.LUA_TSTRING:\n                return \"string\";\n            case LuaState.LUA_TNUMBER:\n                return \"number\";\n            case LuaState.LUA_TBOOLEAN:\n                return \"boolean\";\n            case LuaState.LUA_TFUNCTION:\n                return \"function\";\n            case LuaState.LUA_TTABLE:\n                return \"table\";\n            case LuaState.LUA_TTHREAD:\n                return \"thread\";\n            case LuaState.LUA_TLIGHTUSERDATA:\n            case LuaState.LUA_TUSERDATA:\n                return \"userdata\";\n        }\n        return \"unkown\";\n    }\n\n    /**\n     * Java implementation of the metamethod __index\n     *\n     * @param luaState   int that indicates the state used\n     * @param obj        Object to be indexed\n     * @param methodName the name of the method\n     * @return number of returned objects\n     */\n    public static int setArrayValue(long luaState, Object obj, int index) throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n\n        synchronized (L) {\n            if (obj.getClass().isArray()) {\n                Class<?> type = obj.getClass().getComponentType();\n                try {\n                    Object value = compareTypes(L, type, 3);\n                    Array.set(obj, index, value);\n                } catch (LuaException e) {\n                    argError(L, obj.getClass().getName() + \" [\" + index + \"]\", 3, type);\n                }\n            } else if (obj instanceof List) {\n                ((List<Object>) obj).set(index, L.toJavaObject(3));\n            } else if (obj instanceof Map) {\n                ((Map<Integer, Object>) obj).put(index, L.toJavaObject(3));\n            } else {\n                throw new LuaException(\"can not set \" + obj.getClass().getName() + \" value: \" + L.toJavaObject(3) + \" in \" + index);\n            }\n            return 0;\n        }\n    }\n\n    public static int getArrayValue(long luaState, Object obj, int index) throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n\n        synchronized (L) {\n            Object ret = null;\n            if (obj.getClass().isArray()) {\n                ret = Array.get(obj, index);\n            } else if (obj instanceof List) {\n                ret = ((List) obj).get(index);\n            } else if (obj instanceof Map) {\n                ret = ((Map) obj).get(index);\n            } else {\n                throw new LuaException(\"can not get \" + obj.getClass().getName() + \" value in \" + index);\n            }\n            L.pushObjectValue(ret);\n            return 1;\n        }\n    }\n\n    public static int asTable(long luaState, Object obj) throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n\n        synchronized (L) {\n\n            try {\n                L.newTable();\n                if (obj.getClass().isArray()) {\n                    int n = Array.getLength(obj);\n                    for (int i = 0; i <= n - 1; i++) {\n                        L.pushObjectValue(Array.get(obj, i));\n                        L.rawSetI(-2, i + 1);\n                    }\n                } else if (obj instanceof Collection) {\n                    Collection list = (Collection) obj;\n                    int i = 1;\n                    for (Object v : list) {\n                        L.pushObjectValue(v);\n                        L.rawSetI(-2, i++);\n                    }\n                } else if (obj instanceof Map) {\n                    Map map = (Map) obj;\n                    Iterator itor = map.entrySet().iterator();\n                    while (itor.hasNext()) {\n                        Map.Entry entry = (Map.Entry) itor.next();\n                        L.pushObjectValue(entry.getKey());\n                        L.pushObjectValue(entry.getValue());\n                        L.setTable(-3);\n                    }\n                    /*\n                     for (Map.Entry entry : map.entrySet())\n\t\t\t\t\t { \n\t\t\t\t\t L.pushObjectValue(entry.getKey());\n\t\t\t\t\t L.pushObjectValue(entry.getValue());\n\t\t\t\t\t L.setTable(-3);\n\t\t\t\t\t }*/\n                }\n                L.pushValue(-1);\n                return 1;\n            } catch (Exception e) {\n                throw new LuaException(\"can not astable: \" + e.getMessage());\n            }\n\n        }\n    }\n\n    public static int newArray(long luaState, Class<?> clazz, int size) throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n        synchronized (L) {\n            try {\n                Object obj = Array.newInstance(clazz, size);\n                L.pushJavaObject(obj);\n            } catch (Exception e) {\n                throw new LuaException(\"can not create a array: \" + e.getMessage());\n            }\n            return 1;\n        }\n    }\n\n    public static int newArray(long luaState, Class<?> clazz) throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n        synchronized (L) {\n            try {\n                int top = L.getTop();\n                int[] dimensions = new int[top - 1];\n                for (int i = 0; i < top - 1; i++) {\n                    dimensions[i] = (int) L.toInteger(i + 2);\n                }\n                Object obj = Array.newInstance(clazz, dimensions);\n                L.pushJavaObject(obj);\n            } catch (Exception e) {\n                throw new LuaException(\"can not create a array: \" + e.getMessage());\n            }\n            return 1;\n        }\n    }\n\n    public static Class javaBindClass(String className) throws LuaException {\n        Class clazz;\n        try {\n            clazz = Class.forName(className);\n        } catch (Exception e) {\n            if (className.equals(\"boolean\"))\n                clazz = Boolean.TYPE;\n            else if (className.equals(\"byte\"))\n                clazz = Byte.TYPE;\n            else if (className.equals(\"char\"))\n                clazz = Character.TYPE;\n            else if (className.equals(\"short\"))\n                clazz = Short.TYPE;\n            else if (className.equals(\"int\"))\n                clazz = Integer.TYPE;\n            else if (className.equals(\"long\"))\n                clazz = Long.TYPE;\n            else if (className.equals(\"float\"))\n                clazz = Float.TYPE;\n            else if (className.equals(\"double\"))\n                clazz = Double.TYPE;\n            else\n                throw new LuaException(\"Class not found: \" + className);\n        }\n        return clazz;\n    }\n\n\n    /**\n     * Pushes a new instance of a java Object of the type className\n     *\n     * @param luaState  int that represents the state to be used\n     * @param className name of the class\n     * @return number of returned objects\n     * @throws LuaException\n     */\n    public static int javaNewInstance(long luaState, String className) throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n\n        synchronized (L) {\n            Class clazz;\n            clazz = javaBindClass(className);\n            if (clazz.isPrimitive())\n                return toPrimitive(L, clazz, -1);\n            else\n                return getObjInstance(L, clazz);\n        }\n    }\n\n    /**\n     * javaNew returns a new instance of a given clazz\n     *\n     * @param luaState int that represents the state to be used\n     * @param clazz    class to be instanciated\n     * @return number of returned objects\n     * @throws LuaException\n     */\n    public static int javaNew(long luaState, Class<?> clazz) throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n\n        synchronized (L) {\n            if (clazz.isPrimitive()) {\n                return toPrimitive(L, clazz, -1);\n            } else {\n                return getObjInstance(L, clazz);\n            }\n        }\n    }\n\n    public static int javaCreate(long luaState, Class<?> clazz) throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n\n        synchronized (L) {\n            if (clazz.isInterface()) {\n                return createProxyObject(L, clazz);\n            } else if (clazz.isPrimitive()) {\n                return createArray(L, clazz);\n            } else if (List_class.isAssignableFrom(clazz)) {\n                return createList(L, clazz);\n            } else if (Map_class.isAssignableFrom(clazz)) {\n                return createMap(L, clazz);\n            } else {\n                if (L.objLen(-1) == 0)\n                    return createArray(L, clazz);\n                else if (clazz.isAssignableFrom(new LuaTable(L, -1).get(1).getClass()))\n                    return createArray(L, clazz);\n                else\n                    return getObjInstance(L, clazz);\n\n\n\t\t\t\t/*\n                 LuaTable tab=new LuaTable(L, -1);\n\t\t\t\t tab.push();\n\t\t\t\t if(tab.isList()){\n\t\t\t\t if(tab.isEmpty())\n\t\t\t\t return createArray(L, clazz);\n\t\t\t\t else if(clazz.isAssignableFrom(tab.get(1).getClass()))\n\t\t\t\t return createArray(L, clazz);\n\t\t\t\t else\n\t\t\t\t return getObjInstance(L, clazz);\n\t\t\t\t }\n\t\t\t\t else{\n\t\t\t\t L.setTop(1);\n\t\t\t\t getObjInstance(L, clazz);\n\t\t\t\t LuaObject obj=L.getLuaObject(-1);\n\t\t\t\t Set<LuaTable.LuaEntry> sets=(Set<LuaTable.LuaEntry>)tab.entrySet();\n\t\t\t\t for (LuaTable.LuaEntry entry:sets){\n\t\t\t\t try{\n\t\t\t\t obj.setField((String)entry.getKey(),entry.getValue());\n\t\t\t\t }\n\t\t\t\t catch(Exception e)\n\t\t\t\t {}\n\t\t\t\t }\n\t\t\t\t return 1;\n\t\t\t\t }*/\n            }\n        }\n\n    }\n\n    public static int objectCall(long luaState, Object obj) throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n\n        synchronized (L) {\n            if (obj instanceof LuaMetaTable) {\n                int n = L.getTop();\n                Object[] args = new Object[n - 1];\n                for (int i = 2; i <= n; i++) {\n                    args[i - 2] = L.toJavaObject(i);\n                }\n                Object ret = ((LuaMetaTable) obj).__call(args);\n                L.pushObjectValue(ret);\n                return 1;\n            } else {\n                return 0;\n            }\n        }\n    }\n\n    /**\n     * Function that creates an object proxy and pushes it into the stack\n     *\n     * @param luaState int that represents the state to be used\n     * @param implem   interfaces implemented separated by comma (<code>,</code>)\n     * @return number of returned objects\n     * @throws LuaException\n     */\n    public static int createProxy(long luaState, String implem)\n            throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n        synchronized (L) {\n            return createProxyObject(L, implem);\n        }\n    }\n\n    public static int createArray(long luaState, String className)\n            throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n        synchronized (L) {\n            Class type = javaBindClass(className);\n            return createArray(L, type);\n        }\n    }\n\n    /**\n     * Calls the static method <code>methodName</code> in class <code>className</code>\n     * that receives a LuaState as first parameter.\n     *\n     * @param luaState   int that represents the state to be used\n     * @param className  name of the class that has the open library method\n     * @param methodName method to open library\n     * @return number of returned objects\n     * @throws LuaException\n     */\n    public static int javaLoadLib(long luaState, String className, String methodName)\n            throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n\n        synchronized (L) {\n            Class clazz;\n            try {\n                clazz = Class.forName(className);\n            } catch (ClassNotFoundException e) {\n                throw new LuaException(e);\n            }\n\n            try {\n                Method mt = clazz.getMethod(methodName, new Class[]{LuaState_class});\n                Object obj = mt.invoke(null, new Object[]{L});\n\n                if (obj != null && obj instanceof Integer) {\n                    return ((Integer) obj).intValue();\n                } else\n                    return 0;\n            } catch (Exception e) {\n                throw new LuaException(\"Error on calling method. Library could not be loaded. \" + e.getMessage());\n            }\n        }\n    }\n\n    public static int javaToString(long luaState, Object obj) throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n\n        synchronized (L) {\n            if (obj == null)\n                L.pushString(\"null\");\n            else\n                L.pushString(obj.toString());\n            return 1;\n        }\n    }\n\n    public static int javaEquals(long luaState, Object obj, Object obj2) throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n\n        synchronized (L) {\n            boolean eq = obj.equals(obj2);\n            L.pushBoolean(eq);\n            return 1;\n        }\n    }\n\n    public static int javaObjectLength(long luaState, Object obj) throws LuaException {\n        LuaState L = LuaStateFactory.getExistingState(luaState);\n\n        synchronized (L) {\n            int ret;\n            try {\n                if (obj instanceof CharSequence)\n                    ret = ((CharSequence) obj).length();\n                else if (obj instanceof Collection)\n                    ret = ((Collection) obj).size();\n                else if (obj instanceof Map)\n                    ret = ((Map) obj).size();\n                else\n                    ret = Array.getLength(obj);\n            } catch (Exception e) {\n                throw new LuaException(e);\n            }\n\n            L.pushInteger(ret);\n\n            return 1;\n        }\n    }\n\n\n    private static int getObjInstance(LuaState L, Class<?> clazz) throws LuaException {\n        synchronized (L) {\n            int top = L.getTop();\n            if (top == 1) {\n                try {\n                    Object ret = clazz.newInstance();\n                    L.pushJavaObject(ret);\n                    return 1;\n                } catch (Exception e) {\n                    if (android.view.View.class.isAssignableFrom(clazz)) {\n                        try {\n                            Constructor ctr = clazz.getConstructor(new Class[]{android.content.Context.class});\n                            Object ret = ctr.newInstance(new Object[]{L.getContext()});\n                            L.pushJavaObject(ret);\n                            return 1;\n                        } catch (Exception e2) {\n                        }\n                    }\n                }\n            }\n            Object[] objs = new Object[top - 1];\n\n            Constructor[] constructors = clazz.getConstructors();\n            Constructor constructor = null;\n\n            // gets method and arguments\n            for (int i = 0; i < constructors.length; i++) {\n                Class<?>[] parameters = constructors[i].getParameterTypes();\n                if (parameters.length != top - 1)\n                    continue;\n\n                boolean okConstruc = true;\n\n                for (int j = 0; j < parameters.length; j++) {\n                    try {\n                        objs[j] = compareTypes(L, parameters[j], j + 2);\n                    } catch (Exception e) {\n                        okConstruc = false;\n                        break;\n                    }\n                }\n\n                if (okConstruc) {\n                    constructor = constructors[i];\n                    break;\n                }\n\n            }\n\n            // If method is null means there isn't one receiving the given arguments\n            if (constructor == null) {\n                StringBuilder msgbuilder = new StringBuilder();\n                for (int i = 0; i < constructors.length; i++) {\n                    msgbuilder.append(constructors[i].toString());\n                    msgbuilder.append(\"\\n\");\n                }\n                throw new LuaException(\"Invalid constructor method call. Invalid Parameters.\\n\" + msgbuilder.toString());\n            }\n\n            Object ret;\n            try {\n                ret = constructor.newInstance(objs);\n            } catch (Exception e) {\n                throw new LuaException(e);\n            }\n\n            if (ret == null) {\n                throw new LuaException(\"Couldn't instantiate java Object\");\n            }\n            L.pushJavaObject(ret);\n            return 1;\n        }\n    }\n\n    /**\n     * Checks if there is a field on the obj with the given name\n     *\n     * @param luaState  int that represents the state to be used\n     * @param obj       object to be inspected\n     * @param fieldName name of the field to be inpected\n     * @return number of returned objects\n     */\n    public static int checkField(LuaState L, Object obj, String fieldName)\n            throws LuaException {\n        synchronized (L) {\n            Field field = null;\n            Class objClass;\n            boolean isClass = false;\n\n            if (obj instanceof Class) {\n                objClass = (Class) obj;\n                isClass = true;\n            } else {\n                objClass = obj.getClass();\n            }\n\n            try {\n                field = objClass.getField(fieldName);\n            } catch (NoSuchFieldException e) {\n                return 0;\n            }\n\n            if (field == null)\n                return 0;\n\n            if (isClass && !Modifier.isStatic(field.getModifiers()))\n                return 0;\n\n            Object ret = null;\n            try {\n                if (!Modifier.isPublic(field.getModifiers()))\n                    field.setAccessible(true);\n                ret = field.get(obj);\n            } catch (Exception e) {\n                throw new LuaException(e);\n            }\n\n            L.pushObjectValue(ret);\n            if (Modifier.isFinal(field.getModifiers()))\n                return 5;\n            else\n                return 1;\n        }\n    }\n\n    /**\n     * Checks to see if there is a method with the given name.\n     *\n     * @param luaState   int that represents the state to be used\n     * @param obj        object to be inspected\n     * @param methodName name of the field to be inpected\n     * @return number of returned objects\n     */\n    public static int checkMethod(LuaState L, Object obj, String methodName) throws LuaException {\n        synchronized (L) {\n            Class clazz;\n            boolean isClass = false;\n            if (obj instanceof Class) {\n                clazz = (Class) obj;\n                isClass = true;\n            } else {\n                clazz = obj.getClass();\n            }\n\n            String className = clazz.getName();\n            String cacheName = L.toString(-1);//String.format(\"%c %s %s\",c,className,methodName);\n            Method[] mlist = methodCache.get(cacheName);\n            if (mlist == null) {\n                Method[] methods = methodsMap.get(className);\n                if (methods == null) {\n                    methods = clazz.getMethods();\n                    methodsMap.put(className, methods);\n                }\n                ArrayList<Method> list = new ArrayList<Method>();\n\n                for (int i = 0; i < methods.length; i++) {\n                    if (methods[i].getName().equals(methodName)) {\n                        if (isClass && !Modifier.isStatic(methods[i].getModifiers()))\n                            continue;\n                        list.add(methods[i]);\n                    }\n                }\n\n                if (list.isEmpty() && isClass) {\n                    methods = clazz.getClass().getMethods();\n                    for (int i = 0; i < methods.length; i++) {\n                        if (methods[i].getName().equals(methodName))\n                            list.add(methods[i]);\n                    }\n\n                }\n\n                mlist = new Method[list.size()];\n                list.toArray(mlist);\n                methodCache.put(cacheName, mlist);\n            }\n            if (mlist.length == 0)\n                return 0;\n            return 2;\n        }\n    }\n\n    /**\n     * Checks to see if there is a class with the given name.\n     *\n     * @param L         int that represents the state to be used\n     * @param obj       object to be inspected\n     * @param className name of the field to be inpected\n     * @return number of returned objects\n     */\n    public static int checkClass(LuaState L, Object obj, String className) throws LuaException {\n        synchronized (L) {\n            Class clazz;\n\n            if (obj instanceof Class) {\n                clazz = (Class) obj;\n            } else {\n                return 0;\n            }\n\n            Class[] clazzes = clazz.getClasses();\n\n            for (int i = 0; i < clazzes.length; i++) {\n                if (clazzes[i].getSimpleName().equals(className)) {\n                    L.pushJavaObject(clazzes[i]);\n                    return 3;\n                }\n            }\n            return 0;\n        }\n    }\n\n    public static int javaGetter(LuaState L, Object obj, String methodName) throws LuaException {\n        synchronized (L) {\n            Class clazz;\n\n            Method method = null;\n            boolean isClass = false;\n            if (obj instanceof Map) {\n                Map map = (Map) obj;\n                L.pushObjectValue(map.get(methodName));\n                return 1;\n            } else if (obj instanceof Class) {\n                clazz = (Class) obj;\n                isClass = true;\n            } else {\n                clazz = obj.getClass();\n            }\n\n            try {\n                method = clazz.getMethod(\"get\" + methodName);\n            } catch (NoSuchMethodException e) {\n                return 0;\n            }\n\n            if (isClass && !Modifier.isStatic(method.getModifiers()))\n                return 0;\n\n            Object ret;\n            try {\n                ret = method.invoke(obj);\n            } catch (Exception e) {\n                throw new LuaException(e);\n            }\n\n            if (ret instanceof CharSequence)\n                L.pushString(ret.toString());\n            else\n                L.pushObjectValue(ret);\n            return 1;\n        }\n    }\n\n    public static int javaSetter(LuaState L, Object obj, String methodName) throws LuaException {\n        synchronized (L) {\n            Class clazz;\n            boolean isClass = false;\n\n            if (obj instanceof Map) {\n                Map map = (Map) obj;\n                map.put(methodName, L.toJavaObject(3));\n                return 1;\n            } else if (obj instanceof Class) {\n                clazz = (Class) obj;\n                isClass = true;\n            } else {\n                clazz = obj.getClass();\n            }\n\n            String className = clazz.getName();\n            Method[] methods = methodsMap.get(className);\n            if (methods == null) {\n                methods = clazz.getMethods();\n                methodsMap.put(className, methods);\n            }\n\n            if (methodName.length() > 2 && methodName.substring(0, 2).equals(\"on\") && L.type(-1) == LuaState.LUA_TFUNCTION)\n                return javaSetListener(L, obj, methodName, methods, isClass);\n\n            return javaSetMethod(L, obj, methodName, methods, isClass);\n\n        }\n    }\n\n    private static int javaSetListener(LuaState L, Object obj, String methodName, Method[] methods, boolean isClass) throws LuaException {\n        synchronized (L) {\n            String name = \"setOn\" + methodName.substring(2) + \"Listener\";\n            for (Method m : methods) {\n                if (!m.getName().equals(name))\n                    continue;\n                if (isClass && !Modifier.isStatic(m.getModifiers()))\n                    continue;\n\n                Class<?>[] tp = m.getParameterTypes();\n                if (tp.length == 1 && tp[0].isInterface()) {\n                    L.newTable();\n                    L.pushValue(-2);\n                    L.setField(-2, methodName);\n                    try {\n                        Object listener = L.getLuaObject(-1).createProxy(tp[0]);\n                        m.invoke(obj, new Object[]{listener});\n                        return 1;\n                    } catch (Exception e) {\n                        throw new LuaException(e);\n                    }\n                }\n            }\n        }\n        return 0;\n    }\n\n    private static int javaSetMethod(LuaState L, Object obj, String methodName, Method[] methods, boolean isClass) throws LuaException {\n        synchronized (L) {\n            String name = \"set\" + methodName;\n            Object arg = null;\n            StringBuilder buf = new StringBuilder();\n            for (Method m : methods) {\n                if (!m.getName().equals(name))\n                    continue;\n                if (isClass && !Modifier.isStatic(m.getModifiers()))\n                    continue;\n\n                Class<?>[] tp = m.getParameterTypes();\n                if (tp.length != 1)\n                    continue;\n\n                try {\n                    arg = compareTypes(L, tp[0], -1);\n                } catch (LuaException e) {\n                    buf.append(tp[0]);\n                    buf.append(\"\\n\");\n                    continue;\n                }\n\n                try {\n                    m.invoke(obj, new Object[]{arg});\n                    return 1;\n                } catch (Exception e) {\n                    throw new LuaException(e);\n                }\n\n            }\n            if (buf.length() > 0)\n                throw new LuaException(\"Invalid setter \" + methodName + \". Invalid Parameters.\\n\" + buf.toString() + L.typeName(-1));\n        }\n        return 0;\n    }\n\n    private static int createProxyObject(LuaState L, String implem)\n            throws LuaException {\n        synchronized (L) {\n            try {\n                LuaObject luaObj = L.getLuaObject(2);\n                Object proxy = luaObj.createProxy(implem);\n                L.pushJavaObject(proxy);\n            } catch (Exception e) {\n                throw new LuaException(e);\n            }\n\n            return 1;\n        }\n    }\n\n    private static int createProxyObject(LuaState L, Class implem) throws LuaException {\n        synchronized (L) {\n            L.pushJavaObject(createProxyObject(L, implem, 2));\n            return 1;\n        }\n    }\n\n    private static Object createProxyObject(LuaState L, Class implem, int idx) throws LuaException {\n        synchronized (L) {\n            try {\n                LuaObject luaObj = L.getLuaObject(idx);\n                Object proxy = luaObj.createProxy(implem);\n                return proxy;\n            } catch (Exception e) {\n                throw new LuaException(e);\n            }\n        }\n    }\n\n    private static int createArray(LuaState L, Class<?> type) throws LuaException {\n        synchronized (L) {\n            L.pushJavaObject(createArray(L, type, 2));\n            return 1;\n        }\n    }\n\n    private static Object createArray(LuaState L, Class<?> type, int idx) throws LuaException {\n        synchronized (L) {\n            try {\n                int n = L.objLen(idx);\n                Object array = Array.newInstance(type, n);\n\n                if (type == String_class) {\n                    for (int i = 1; i <= n; i++) {\n                        L.pushNumber(i);\n                        L.getTable(idx);\n                        Array.set(array, i - 1, L.toString(-1));\n                        L.pop(1);\n                    }\n                } else if (type == Double.TYPE) {\n                    for (int i = 1; i <= n; i++) {\n                        L.pushNumber(i);\n                        L.getTable(idx);\n                        Array.set(array, i - 1, L.toNumber(-1));\n                        L.pop(1);\n                    }\n                } else if (type == Float.TYPE) {\n                    for (int i = 1; i <= n; i++) {\n                        L.pushNumber(i);\n                        L.getTable(idx);\n                        Array.set(array, i - 1, (float) L.toNumber(-1));\n                        L.pop(1);\n                    }\n                } else if (type == Long.TYPE) {\n                    for (int i = 1; i <= n; i++) {\n                        L.pushNumber(i);\n                        L.getTable(idx);\n                        Array.set(array, i - 1, L.toInteger(-1));\n                        L.pop(1);\n                    }\n                } else if (type == Integer.TYPE) {\n                    for (int i = 1; i <= n; i++) {\n                        L.pushNumber(i);\n                        L.getTable(idx);\n                        Array.set(array, i - 1, (int) L.toInteger(-1));\n                        L.pop(1);\n                    }\n                } else if (type == Short.TYPE) {\n                    for (int i = 1; i <= n; i++) {\n                        L.pushNumber(i);\n                        L.getTable(idx);\n                        Array.set(array, i - 1, (short) L.toInteger(-1));\n                        L.pop(1);\n                    }\n                } else if (type == Character.TYPE) {\n                    for (int i = 1; i <= n; i++) {\n                        L.pushNumber(i);\n                        L.getTable(idx);\n                        Array.set(array, i - 1, (char) L.toInteger(-1));\n                        L.pop(1);\n                    }\n                } else if (type == Byte.TYPE) {\n                    for (int i = 1; i <= n; i++) {\n                        L.pushNumber(i);\n                        L.getTable(idx);\n                        Array.set(array, i - 1, (byte) L.toInteger(-1));\n                        L.pop(1);\n                    }\n                } else {\n                    for (int i = 1; i <= n; i++) {\n                        L.pushNumber(i);\n                        L.getTable(idx);\n                        Array.set(array, i - 1, compareTypes(L, type, -1));\n                        L.pop(1);\n                    }\n                }\n                return array;\n            } catch (Exception e) {\n                throw new LuaException(e);\n            }\n        }\n    }\n\n    private static int createList(LuaState L, Class<?> type) throws LuaException {\n        synchronized (L) {\n            L.pushJavaObject(createList(L, type, 2));\n            return 1;\n        }\n    }\n\n    private static Object createList(LuaState L, Class<?> type, int idx) throws LuaException {\n        synchronized (L) {\n            int n = L.objLen(idx);\n            try {\n                if (type.equals(List_class))\n                    type = ArrayList_class;\n                List<Object> list = (List<Object>) type.newInstance();\n                for (int i = 1; i <= n; i++) {\n                    L.pushNumber(i);\n                    L.getTable(idx);\n                    list.add(L.toJavaObject(-1));\n                    L.pop(1);\n                }\n                return list;\n            } catch (Exception e) {\n                throw new LuaException(e);\n            }\n        }\n    }\n\n\n    private static int createMap(LuaState L, Class<?> clazz) throws LuaException {\n        // TODO: Implement this method\n        synchronized (L) {\n            L.pushJavaObject(createMap(L, clazz, 2));\n            return 1;\n        }\n    }\n\n    private static Object createMap(LuaState L, Class<?> clazz, int idx) throws LuaException {\n        // TODO: Implement this method\n        synchronized (L) {\n            try {\n                if (clazz.equals(Map_class))\n                    clazz = HashMap_class;\n                Map<Object, Object> map = (Map<Object, Object>) clazz.newInstance();\n                L.pushNil();\n                while (L.next(idx) != 0) {\n                    map.put(L.toJavaObject(-2), L.toJavaObject(-1));\n                    L.pop(1);\n                }\n                return map;\n            } catch (Exception e) {\n                throw new LuaException(e);\n            }\n        }\n    }\n\n\n    private static Object compareTypes(LuaState L, Class<?> parameter, int idx)\n            throws LuaException {\n        boolean okType = true;\n        Object obj = null;\n        int type = L.type(idx);\n        switch (type) {\n            case 1: //boolean\n            {\n                if (parameter.isPrimitive()) {\n                    if (parameter != Boolean.TYPE) {\n                        okType = false;\n                    }\n                } else if (!parameter.isAssignableFrom(Boolean.TYPE)) {\n                    okType = false;\n                }\n                obj = L.toBoolean(idx);\n            }\n            break;\n            case 4: //string\n            {\n                if (!parameter.isAssignableFrom(String_class)) {\n                    okType = false;\n                } else {\n                    obj = L.toString(idx);\n                }\n            }\n            break;\n            case 6: //function\n            {\n                if (!parameter.isAssignableFrom(LuaFunction_class)) {\n                    okType = false;\n                } else {\n                    obj = L.getLuaObject(idx);\n                }\n            }\n            break;\n            case 5: //table\n            {\n                if (parameter.isAssignableFrom(LuaTable_class)) {\n                    obj = L.getLuaObject(idx);\n                } else if (parameter.isArray()) {\n                    obj = createArray(L, parameter.getComponentType(), idx);\n                } else if (parameter.isInterface()) {\n                    obj = createProxyObject(L, parameter, idx);\n                } else if (Map_class.isAssignableFrom(parameter)) {\n                    obj = createMap(L, parameter, idx);\n                } else {\n                    okType = false;\n                }\n            }\n            break;\n            case 3: //number\n            {\n                if (L.isInteger(idx)) {\n                    Long lg = new Long(L.toInteger(idx));\n                    obj = LuaState.convertLuaNumber(lg, parameter);\n                } else {\n                    Double db = new Double(L.toNumber(idx));\n                    obj = LuaState.convertLuaNumber(db, parameter);\n                }\n                if (obj == null) {\n                    okType = false;\n                }\n            }\n            break;\n            case 7: //userdata\n            {\n                if (L.isObject(idx)) {\n                    Object userObj = L.getObjectFromUserdata(idx);\n                    if (userObj == null) {\n                        obj = null;\n                    } else if (parameter.isPrimitive() && (Number_class.isAssignableFrom(userObj.getClass()) || Character_class.isAssignableFrom(userObj.getClass()))) {\n                        obj = userObj;\n                    } else if (parameter.isAssignableFrom(userObj.getClass())) {\n                        obj = userObj;\n                    } else {\n                        okType = false;\n                    }\n                } else {\n                    if (!parameter.isAssignableFrom(LuaObject_class)) {\n                        okType = false;\n                    } else {\n                        obj = L.getLuaObject(idx);\n                    }\n                }\n            }\n            break;\n            case 0: //nil\n            {\n                obj = null;\n            }\n            break;\n            default: //other\n            {\n                throw new LuaException(\"Invalid Parameters.\");\n            }\n        }\n        if (!okType) {\n            throw new LuaException(\"Invalid Parameter.\");\n        }\n\n        return obj;\n    }\n\n\n    private static int toPrimitive(LuaState L, Class type, int idx) throws LuaException {\n        Object obj = null;\n\n        if (type == Character.TYPE && L.type(idx) == LuaState.LUA_TSTRING) {\n            String s = L.toString(idx);\n            if (s == null) {\n                obj = \"\";\n            } else if (s.length() == 1) {\n                obj = s.charAt(0);\n            } else {\n                obj = s.toCharArray();\n            }\n        } else if (!L.isNumber(idx)) {\n            throw new LuaException(L.toString(idx) + \" is not number\");\n        } else if (type == Double.TYPE) {\n            obj = L.toNumber(idx);\n        } else if (type == Float.TYPE) {\n            obj = (float) L.toNumber(idx);\n        } else if (type == Long.TYPE) {\n            obj = L.toInteger(idx);\n        } else if (type == Integer.TYPE) {\n            obj = (int) L.toInteger(idx);\n        } else if (type == Short.TYPE) {\n            obj = (short) L.toInteger(idx);\n        } else if (type == Character.TYPE) {\n            obj = (char) L.toInteger(idx);\n        } else if (type == Byte.TYPE) {\n            obj = (byte) L.toInteger(idx);\n        } else if (type == Boolean.TYPE) {\n            obj = L.toBoolean(idx);\n        }\n        L.pushJavaObject(obj);\n        return 1;\n    }\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/LuaList.java",
    "content": "package com.luajava;\n\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.ListIterator;\n\npublic class LuaList extends LuaObject implements List {\n\n    protected LuaList(LuaState L, String globalName) {\n        super(L, globalName);\n    }\n\n    protected LuaList(LuaState L, int index) {\n        super(L, index);\n    }\n\n    public LuaList(LuaState L) {\n        super(L);\n        L.newTable();\n        registerValue(-1);\n    }\n\n    @Override\n    public void clear() {\n        // TODO: Implement this method\n    }\n\n    @Override\n    public boolean isEmpty() {\n        // TODO: Implement this method\n        push();\n        int len = L.rawLen(-1);\n        L.pop(1);\n        return len == 0;\n    }\n\n    @Override\n    public boolean remove(Object p1) {\n        // TODO: Implement this method\n        return false;\n    }\n\n    @Override\n    public int size() {\n        // TODO: Implement this method\n        push();\n        int len = L.rawLen(-1);\n        L.pop(1);\n        return len;\n    }\n\n    @Override\n    public void add(int p1, Object p2) {\n        // TODO: Implement this method\n    }\n\n    @Override\n    public boolean add(Object p1) {\n        // TODO: Implement this method\n        push();\n        int len = L.rawLen(-1);\n        try {\n            L.pushObjectValue(p1);\n            L.setI(-2, len + 1);\n            pop();\n            return true;\n        } catch (LuaException e) {\n            pop();\n            return false;\n        }\n    }\n\n    @Override\n    public boolean addAll(int p1, Collection p2) {\n        // TODO: Implement this method\n        return false;\n    }\n\n    @Override\n    public boolean addAll(Collection p1) {\n        // TODO: Implement this method\n        return false;\n    }\n\n    @Override\n    public boolean contains(Object p1) {\n        // TODO: Implement this method\n        return false;\n    }\n\n    @Override\n    public boolean containsAll(Collection p1) {\n        // TODO: Implement this method\n        return false;\n    }\n\n    @Override\n    public Object get(int p1) {\n        // TODO: Implement this method\n        return null;\n    }\n\n    @Override\n    public int indexOf(Object p1) {\n        // TODO: Implement this method\n        return 0;\n    }\n\n    @Override\n    public Iterator iterator() {\n        // TODO: Implement this method\n        return null;\n    }\n\n    @Override\n    public int lastIndexOf(Object p1) {\n        // TODO: Implement this method\n        return 0;\n    }\n\n    @Override\n    public ListIterator listIterator() {\n        // TODO: Implement this method\n        return null;\n    }\n\n    @Override\n    public ListIterator listIterator(int p1) {\n        // TODO: Implement this method\n        return null;\n    }\n\n    @Override\n    public Object remove(int p1) {\n        // TODO: Implement this method\n        return null;\n    }\n\n    @Override\n    public boolean removeAll(Collection p1) {\n        // TODO: Implement this method\n        return false;\n    }\n\n    @Override\n    public boolean retainAll(Collection p1) {\n        // TODO: Implement this method\n        return false;\n    }\n\n    @Override\n    public Object set(int p1, Object p2) {\n        // TODO: Implement this method\n        return null;\n    }\n\n    @Override\n    public List subList(int p1, int p2) {\n        // TODO: Implement this method\n        return null;\n    }\n\n    @Override\n    public Object[] toArray() {\n        // TODO: Implement this method\n        return null;\n    }\n\n    @Override\n    public Object[] toArray(Object[] p1) {\n        // TODO: Implement this method\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/LuaMetaTable.java",
    "content": "package com.luajava;\n\npublic interface LuaMetaTable {\n    public Object __call(Object... arg) throws LuaException;\n\n    public Object __index(String key);\n\n    public void __newIndex(String key, Object value);\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/LuaObject.java",
    "content": "/*\n * $Id: LuaObject.java,v 1.6 2006/12/22 14:06:40 thiago Exp $\n * Copyright (C) 2003-2007 Kepler Project.\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\npackage com.luajava;\n\nimport java.lang.reflect.Array;\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Proxy;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.StringTokenizer;\n\n/**\n * This class represents a Lua object of any type. A LuaObject is constructed by a {@link LuaState} object using one of\n * the four methods:\n * <ul>\n * <li>{@link LuaState#getLuaObject(String globalName)}</li>\n * <li>{@link LuaState#getLuaObject(LuaObject parent, String name)}</li>\n * <li>{@link LuaState#getLuaObject(LuaObject parent, Number name)}</li>\n * <li>{@link LuaState#getLuaObject(LuaObject parent, LuaObject name)}</li>\n * <li>{@link LuaState#getLuaObject(int index)}</li>\n * </ul>\n * The LuaObject will represent only the object itself, not a variable or a stack index, so when you change a string,\n * remember that strings are immutable objects in Lua, and the LuaObject you have will represent the old one.\n * <p>\n * <h2>Proxies</h2>\n * <p>\n * LuaJava allows you to implement a class in Lua, like said before. If you want to create this proxy from Java, you\n * should have a LuaObject representing the table that has the functions that implement the interface. From this\n * LuaObject you can call the <code>createProxy(String implements)</code>. This method receives the string with the\n * name of the interfaces implemented by the object separated by comma.\n *\n * @author Rizzato\n * @author Thiago Ponte\n */\npublic class LuaObject {\n    protected int ref;\n\n    protected LuaState L;\n\n\n    protected LuaObject(LuaState L) {\n        this.L = L;\n    }\n\n    /**\n     * Creates a reference to an object in the variable globalName\n     *\n     * @param L\n     * @param globalName\n     */\n    protected LuaObject(LuaState L, String globalName) {\n        synchronized (L) {\n            this.L = L;\n            L.getGlobal(globalName);\n            registerValue(-1);\n            L.pop(1);\n        }\n    }\n\n    /**\n     * Creates a reference to an object inside another object\n     *\n     * @param parent The Lua Table or Userdata that contains the Field.\n     * @param name   The name that index the field\n     */\n    protected LuaObject(LuaObject parent, String name) throws LuaException {\n        synchronized (parent.getLuaState()) {\n            this.L = parent.getLuaState();\n\n            if (!parent.isTable() && !parent.isUserdata()) {\n                throw new LuaException(\"Object parent should be a table or userdata .\");\n            }\n\n            parent.push();\n            L.pushString(name);\n            L.getTable(-2);\n            L.remove(-2);\n            registerValue(-1);\n            L.pop(1);\n        }\n    }\n\n    /**\n     * This constructor creates a LuaObject from a table that is indexed by a number.\n     *\n     * @param parent The Lua Table or Userdata that contains the Field.\n     * @param name   The name (number) that index the field\n     * @throws LuaException When the parent object isn't a Table or Userdata\n     */\n    protected LuaObject(LuaObject parent, Number name) throws LuaException {\n        synchronized (parent.getLuaState()) {\n            this.L = parent.getLuaState();\n            if (!parent.isTable() && !parent.isUserdata())\n                throw new LuaException(\"Object parent should be a table or userdata .\");\n\n            parent.push();\n            L.pushNumber(name.doubleValue());\n            L.getTable(-2);\n            L.remove(-2);\n            registerValue(-1);\n            L.pop(1);\n        }\n    }\n\n    /**\n     * This constructor creates a LuaObject from a table that is indexed by a LuaObject.\n     *\n     * @param parent The Lua Table or Userdata that contains the Field.\n     * @param name   The name (LuaObject) that index the field\n     * @throws LuaException When the parent object isn't a Table or Userdata\n     */\n    protected LuaObject(LuaObject parent, LuaObject name) throws LuaException {\n        if (parent.getLuaState() != name.getLuaState())\n            throw new LuaException(\"LuaStates must be the same!\");\n        synchronized (parent.getLuaState()) {\n            if (!parent.isTable() && !parent.isUserdata())\n                throw new LuaException(\"Object parent should be a table or userdata .\");\n\n            this.L = parent.getLuaState();\n\n            parent.push();\n            name.push();\n            L.getTable(-2);\n            L.remove(-2);\n            registerValue(-1);\n            L.pop(1);\n        }\n    }\n\n    /**\n     * Creates a reference to an object in the given index of the stack\n     *\n     * @param L\n     * @param index of the object on the lua stack\n     */\n    protected LuaObject(LuaState L, int index) {\n        synchronized (L) {\n            this.L = L;\n\n            registerValue(index);\n        }\n    }\n\n    /**\n     * Gets the Object's State\n     */\n    public LuaState getLuaState() {\n        return L;\n    }\n\n    /**\n     * Creates the reference to the object in the registry table\n     *\n     * @param index of the object on the lua stack\n     */\n    protected void registerValue(int index) {\n        synchronized (L) {\n            L.pushValue(index);\n            int key;\n            ref = L.Lref(LuaState.LUA_REGISTRYINDEX);\n            //\t\t\tref = new Integer(key);\n        }\n    }\n\n    protected void finalize() {\n        try {\n            synchronized (L) {\n                if (L.getPointer() != 0)\n                    L.LunRef(LuaState.LUA_REGISTRYINDEX, ref);\n            }\n        } catch (Exception e) {\n            System.err.println(\"Unable to release object \" + ref);\n        }\n    }\n\n    /**\n     * Pushes the object represented by <code>this<code> into L's stack\n     */\n    public void push() {\n        L.rawGetI(LuaState.LUA_REGISTRYINDEX, ref);\n    }\n\n    public void pop() {\n        L.pop(1);\n    }\n\n    public boolean isNil() {\n        synchronized (L) {\n            push();\n            boolean bool = L.isNil(-1);\n            L.pop(1);\n            return bool;\n        }\n    }\n\n    public boolean isBoolean() {\n        synchronized (L) {\n            push();\n            boolean bool = L.isBoolean(-1);\n            L.pop(1);\n            return bool;\n        }\n    }\n\n    public boolean isNumber() {\n        synchronized (L) {\n            push();\n            boolean bool = L.isNumber(-1);\n            L.pop(1);\n            return bool;\n        }\n    }\n\n    public boolean isInteger() {\n        synchronized (L) {\n            push();\n            boolean bool = L.isInteger(-1);\n            L.pop(1);\n            return bool;\n        }\n    }\n\n    public boolean isString() {\n        synchronized (L) {\n            push();\n            boolean bool = L.isString(-1);\n            L.pop(1);\n            return bool;\n        }\n    }\n\n    public boolean isFunction() {\n        synchronized (L) {\n            push();\n            boolean bool = L.isFunction(-1);\n            L.pop(1);\n            return bool;\n        }\n    }\n\n    public boolean isJavaObject() {\n        synchronized (L) {\n            push();\n            boolean bool = L.isObject(-1);\n            L.pop(1);\n            return bool;\n        }\n    }\n\n    public boolean isJavaFunction() {\n        synchronized (L) {\n            push();\n            boolean bool = L.isJavaFunction(-1);\n            L.pop(1);\n            return bool;\n        }\n    }\n\n    public boolean isTable() {\n        synchronized (L) {\n            push();\n            boolean bool = L.isTable(-1);\n            L.pop(1);\n            return bool;\n        }\n    }\n\n    public boolean isUserdata() {\n        synchronized (L) {\n            push();\n            boolean bool = L.isUserdata(-1);\n            L.pop(1);\n            return bool;\n        }\n    }\n\n    public int type() {\n        synchronized (L) {\n            push();\n            int type = L.type(-1);\n            L.pop(1);\n            return type;\n        }\n    }\n\n    public boolean getBoolean() {\n        synchronized (L) {\n            push();\n            boolean bool = L.toBoolean(-1);\n            L.pop(1);\n            return bool;\n        }\n    }\n\n    public double getNumber() {\n        synchronized (L) {\n            push();\n            double db = L.toNumber(-1);\n            L.pop(1);\n            return db;\n        }\n    }\n\n    public long getInteger() {\n        synchronized (L) {\n            push();\n            long lg = L.toInteger(-1);\n            L.pop(1);\n            return lg;\n        }\n    }\n\n    public String getString() {\n        synchronized (L) {\n            push();\n            String str = L.toString(-1);\n            L.pop(1);\n            return str;\n        }\n    }\n\n    public LuaTable<?, ?> getTable() {\n        synchronized (L) {\n            push();\n            LuaTable td = new LuaTable(L, -1);\n            L.pop(1);\n            return td;\n        }\n    }\n\n    public LuaFunction<?> getFunction() {\n        synchronized (L) {\n            push();\n            LuaFunction ft = new LuaFunction(L, -1);\n            L.pop(1);\n            return ft;\n        }\n    }\n\n\n    public Object getObject() throws LuaException {\n        synchronized (L) {\n            push();\n            Object obj = L.getObjectFromUserdata(-1);\n            L.pop(1);\n            return obj;\n        }\n    }\n\n    /**\n     * If <code>this<code> is a table or userdata tries to set\n     * a field value.\n     */\n    public LuaObject getField(String field) throws LuaException {\n        return L.getLuaObject(this, field);\n    }\n\n    public void setField(String field, Object obj) {\n        push();\n        try {\n            L.pushObjectValue(obj);\n        } catch (LuaException e) {\n            L.pushNil();\n        }\n        L.setField(-2, field);\n        L.pop(1);\n    }\n\n    public LuaObject getI(long idx) throws LuaException {\n        return L.getLuaObject(this, idx);\n    }\n\n    public void setI(long idx, Object obj) {\n        push();\n        try {\n            L.pushObjectValue(obj);\n        } catch (LuaException e) {\n            L.pushNil();\n        }\n        L.setI(-2, idx);\n        L.pop(1);\n    }\n\n    /**\n     * Calls the object represented by <code>this</code> using Lua function pcall.\n     *\n     * @param args -\n     *             Call arguments\n     * @param nres -\n     *             Number of objects returned\n     * @return Object[] - Returned Objects\n     * @throws LuaException\n     */\n    public Object[] callx(Object[] args, int nres) throws LuaException {\n        synchronized (L) {\n            if (!isFunction() && !isTable() && !isUserdata())\n                throw new LuaException(\"Invalid object. Not a function, table or userdata .\");\n\n            int top = L.getTop();\n            push();\n            int nargs;\n            if (args != null) {\n                nargs = args.length;\n                for (int i = 0; i < nargs; i++) {\n                    Object obj = args[i];\n                    L.pushObjectValue(obj);\n                }\n            } else\n                nargs = 0;\n\n            int err = L.pcall(nargs, nres, 0);\n\n            if (err != 0) {\n                String str;\n                if (L.isString(-1)) {\n                    str = L.toString(-1);\n                    L.pop(1);\n                } else\n                    str = \"\";\n\n                if (err == LuaState.LUA_ERRRUN) {\n                    str = \"Runtime error. \" + str;\n                } else if (err == LuaState.LUA_ERRMEM) {\n                    str = \"Memory allocation error. \" + str;\n                } else if (err == LuaState.LUA_ERRERR) {\n                    str = \"Error while running the error handler function. \" + str;\n                } else {\n                    str = \"Lua Error code \" + err + \". \" + str;\n                }\n\n                throw new LuaException(str);\n            }\n\n            if (nres == LuaState.LUA_MULTRET)\n                nres = L.getTop() - top;\n            if (L.getTop() - top < nres) {\n                throw new LuaException(\"Invalid Number of Results .\");\n            }\n\n            Object[] res = new Object[nres];\n\n            for (int i = nres; i > 0; i--) {\n                res[i - 1] = L.toJavaObject(-1);\n                L.pop(1);\n            }\n            return res;\n        }\n    }\n\n    /**\n     * Calls the object represented by <code>this</code> using Lua function pcall. Returns 1 object\n     *\n     * @param args -\n     *             Call arguments\n     * @return Object - Returned Object\n     * @throws LuaException\n     */\n    public Object call(Object... args) throws LuaException {\n        return callx(args, 1)[0];\n    }\n\n    public byte[] dump() throws LuaException {\n        synchronized (L) {\n            if (!isFunction())\n                throw new LuaException(\"Invalid object. Not a function .\");\n\n            push();\n            byte[] buf = L.dump(-1);\n            L.pop(1);\n            return buf;\n        }\n    }\n\n    public Object[] asArray() throws IllegalArgumentException, ArrayIndexOutOfBoundsException, LuaException {\n        synchronized (L) {\n            if (!isTable())\n                throw new LuaException(\"Invalid object. Not a table .\");\n            push();\n            int n = L.objLen(-1);\n            Object array = Array.newInstance(Object.class, n);\n            for (int i = 1; i <= n; i++) {\n                L.pushInteger(i);\n                L.getTable(-2);\n                try {\n                    Array.set(array, i - 1, L.toJavaObject(-1));\n                } catch (LuaException e) {\n                }\n                L.pop(1);\n            }\n            L.pop(1);\n            return (Object[]) array;\n        }\n    }\n\n    public Map asMap(LuaState L, Class<?> clazz, int idx) throws LuaException {\n        // TODO: Implement this method\n        synchronized (L) {\n            if (!isTable())\n                throw new LuaException(\"Invalid object. Not a table .\");\n            HashMap<Object, Object> map = new HashMap<Object, Object>();\n            push();\n            L.pushNil();\n            while (L.next(idx) != 0) {\n                try {\n                    map.put(L.toJavaObject(-2), L.toJavaObject(-1));\n                } catch (LuaException e) {\n                }\n                L.pop(1);\n            }\n            L.pop(1);\n            return map;\n        }\n    }\n\n    public String toString() {\n        synchronized (L) {\n            try {\n                if (isNil())\n                    return \"nil\";\n                else if (isBoolean())\n                    return String.valueOf(getBoolean());\n                else if (isNumber())\n                    return String.valueOf(getNumber());\n                else if (isString())\n                    return getString();\n                else if (isFunction())\n                    return \"Lua Function\";\n                else if (isJavaObject())\n                    return getObject().toString();\n                else if (isUserdata())\n                    return \"Userdata\";\n                else if (isTable())\n                    return \"Lua Table\";\n                else if (isJavaFunction())\n                    return \"Java Function\";\n                else\n                    return null;\n            } catch (LuaException e) {\n                return null;\n            }\n        }\n    }\n\n    /**\n     * Function that creates a java proxy to the object represented by <code>this</code>\n     *\n     * @param implem Interfaces that are implemented, separated by <code>,</code>\n     */\n    public Object createProxy(String implem) throws ClassNotFoundException, LuaException {\n        synchronized (L) {\n            if (!isTable())\n                throw new LuaException(\"Invalid Object. Must be Table.\");\n\n            StringTokenizer st = new StringTokenizer(implem, \",\");\n            Class[] interfaces = new Class[st.countTokens()];\n            for (int i = 0; st.hasMoreTokens(); i++)\n                interfaces[i] = Class.forName(st.nextToken());\n\n            InvocationHandler handler = new LuaInvocationHandler(this);\n\n            return Proxy.newProxyInstance(this.getClass().getClassLoader(), interfaces, handler);\n        }\n    }\n\n    public Object createProxy(Class implem) throws LuaException {\n        synchronized (L) {\n            if (!isTable())\n                throw new LuaException(\"Invalid Object. Must be Table.\");\n\n            Class[] interfaces = new Class[]{implem};\n\n            InvocationHandler handler = new LuaInvocationHandler(this);\n\n            return Proxy.newProxyInstance(implem.getClassLoader(), interfaces, handler);\n        }\n    }\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/LuaStack.java",
    "content": "package com.luajava;\n\nimport java.util.HashMap;\n\npublic class LuaStack {\n    private final static HashMap<String, LuaState> luaStack = new HashMap<String, LuaState>();\n\n    public static void put(String name, LuaState L) {\n        luaStack.put(name, L);\n    }\n\n    public static LuaState get(String name) {\n        return luaStack.get(name);\n    }\n\n    public static Object call(String name, String func, Object[] arg) throws LuaException {\n        return new LuaFunction(get(name), func).call(arg);\n    }\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/LuaState.java",
    "content": "package com.luajava;\n\nimport androlua.LuaContext;\n\npublic class LuaState {\n    public static final int LUAI_MAXSTACK = 1000000;\n    public static final int LUA_ERRERR = 6;\n    public static final int LUA_ERRGCMM = 5;\n    public static final int LUA_ERRMEM = 4;\n    public static final int LUA_ERRRUN = 2;\n    public static final int LUA_ERRSYNTAX = 3;\n    public static final int LUA_GCCOLLECT = 2;\n    public static final int LUA_GCCOUNT = 3;\n    public static final int LUA_GCCOUNTB = 4;\n    public static final int LUA_GCRESTART = 1;\n    public static final int LUA_GCSETPAUSE = 6;\n    public static final int LUA_GCSETSTEPMUL = 7;\n    public static final int LUA_GCSTEP = 5;\n    public static final int LUA_GCSTOP = 0;\n    public static final int LUA_MULTRET = -1;\n    public static final int LUA_OPEQ = 0;\n    public static final int LUA_OPLE = 2;\n    public static final int LUA_OPLT = 1;\n    public static final int LUA_REGISTRYINDEX = -1001000;\n    public static final int LUA_RIDX_GLOBALS = 2;\n    public static final int LUA_RIDX_LAST = 2;\n    public static final int LUA_RIDX_MAINTHREAD = 1;\n    public static final int LUA_TBOOLEAN = 1;\n    public static final int LUA_TFUNCTION = 6;\n    public static final int LUA_TLIGHTUSERDATA = 2;\n    public static final int LUA_TNIL = 0;\n    public static final int LUA_TNONE = -1;\n    public static final int LUA_TNUMBER = 3;\n    public static final int LUA_TSTRING = 4;\n    public static final int LUA_TTABLE = 5;\n    public static final int LUA_TTHREAD = 8;\n    public static final int LUA_TUSERDATA = 7;\n    public static final int LUA_YIELD = 1;\n    private static final String LUAJAVA_LIB = \"luajava\";\n    private static Class<?> Byte_class = Byte.class;\n    private static Class<?> Double_class = Double.class;\n    private static Class<?> Float_class = Float.class;\n    private static Class<?> Integer_class = Integer.class;\n    private static Class<?> Long_class = Long.class;\n    private static Class<?> Number_class = Number.class;\n    private static Class<?> Short_class = Short.class;\n\n    static {\n        System.loadLibrary(LUAJAVA_LIB);\n    }\n\n    private long luaState;\n    private LuaContext mContext;\n\n    protected LuaState() {\n        this.luaState = _newstate();\n    }\n\n    protected LuaState(long luaState) {\n        this.luaState = luaState;\n        LuaStateFactory.insertLuaState(this);\n    }\n\n    public static Number convertLuaNumber(Double db, Class<?> retType) {\n        if (retType.isPrimitive()) {\n            if (retType == Integer.TYPE) {\n                return Integer.valueOf(db.intValue());\n            }\n            if (retType == Long.TYPE) {\n                return Long.valueOf(db.longValue());\n            }\n            if (retType == Float.TYPE) {\n                return Float.valueOf(db.floatValue());\n            }\n            if (retType == Double.TYPE) {\n                return Double.valueOf(db.doubleValue());\n            }\n            if (retType == Byte.TYPE) {\n                return Byte.valueOf(db.byteValue());\n            }\n            if (retType == Short.TYPE) {\n                return Short.valueOf(db.shortValue());\n            }\n        } else if (retType.isAssignableFrom(Number_class)) {\n            if (retType.isAssignableFrom(Integer_class)) {\n                return new Integer(db.intValue());\n            }\n            if (retType.isAssignableFrom(Long_class)) {\n                return new Long(db.longValue());\n            }\n            if (retType.isAssignableFrom(Float_class)) {\n                return new Float(db.floatValue());\n            }\n            if (retType.isAssignableFrom(Double_class)) {\n                return db;\n            }\n            if (retType.isAssignableFrom(Byte_class)) {\n                return new Byte(db.byteValue());\n            }\n            if (retType.isAssignableFrom(Short_class)) {\n                return new Short(db.shortValue());\n            }\n        }\n        return null;\n    }\n\n    public static Number convertLuaNumber(Long lg, Class<?> retType) {\n        if (retType.isPrimitive()) {\n            if (retType == Integer.TYPE) {\n                return Integer.valueOf(lg.intValue());\n            }\n            if (retType == Long.TYPE) {\n                return Long.valueOf(lg.longValue());\n            }\n            if (retType == Float.TYPE) {\n                return Float.valueOf(lg.floatValue());\n            }\n            if (retType == Double.TYPE) {\n                return Double.valueOf(lg.doubleValue());\n            }\n            if (retType == Byte.TYPE) {\n                return Byte.valueOf(lg.byteValue());\n            }\n            if (retType == Short.TYPE) {\n                return Short.valueOf(lg.shortValue());\n            }\n        } else if (retType.isAssignableFrom(Number_class)) {\n            if (retType.isAssignableFrom(Integer_class)) {\n                return new Integer(lg.intValue());\n            }\n            if (retType.isAssignableFrom(Long_class)) {\n                return new Long(lg.longValue());\n            }\n            if (retType.isAssignableFrom(Float_class)) {\n                return new Float(lg.floatValue());\n            }\n            if (retType.isAssignableFrom(Double_class)) {\n                return lg;\n            }\n            if (retType.isAssignableFrom(Byte_class)) {\n                return new Byte(lg.byteValue());\n            }\n            if (retType.isAssignableFrom(Short_class)) {\n                return new Short(lg.shortValue());\n            }\n        }\n        return null;\n    }\n\n    private native synchronized int _LargError(long j, int i, String str);\n\n    private native synchronized int _LcallMeta(long j, int i, String str);\n\n    private native synchronized void _LcheckAny(long j, int i);\n\n    private native synchronized int _LcheckInteger(long j, int i);\n\n    private native synchronized double _LcheckNumber(long j, int i);\n\n    private native synchronized void _LcheckStack(long j, int i, String str);\n\n    private native synchronized String _LcheckString(long j, int i);\n\n    private native synchronized void _LcheckType(long j, int i, int i2);\n\n    private native synchronized int _LdoFile(long j, String str);\n\n    private native synchronized int _LdoString(long j, String str);\n\n    private native synchronized int _LgetMetaField(long j, int i, String str);\n\n    private native synchronized void _LgetMetatable(long j, String str);\n\n    private native synchronized String _Lgsub(long j, String str, String str2, String str3);\n\n    private native synchronized int _LloadBuffer(long j, byte[] bArr, long j2, String str);\n\n    private native synchronized int _LloadFile(long j, String str);\n\n    private native synchronized int _LloadString(long j, String str);\n\n    private native synchronized int _LnewMetatable(long j, String str);\n\n    private native synchronized int _LoptInteger(long j, int i, int i2);\n\n    private native synchronized double _LoptNumber(long j, int i, double d);\n\n    private native synchronized String _LoptString(long j, int i, String str);\n\n    private native synchronized int _Lref(long j, int i);\n\n    private native synchronized void _LunRef(long j, int i, int i2);\n\n    private native synchronized void _Lwhere(long j, int i);\n\n    private native synchronized void _call(long j, int i, int i2);\n\n    private native synchronized int _checkStack(long j, int i);\n\n    private native synchronized void _close(long j);\n\n    private native synchronized int _compare(long j, int i, int i2, int i3);\n\n    private native synchronized void _concat(long j, int i);\n\n    private native synchronized void _copy(long j, int i, int i2);\n\n    private native synchronized void _createTable(long j, int i, int i2);\n\n    private native synchronized byte[] _dump(long j, int i);\n\n    private native synchronized int _equal(long j, int i, int i2);\n\n    private native synchronized int _error(long j);\n\n    private native synchronized int _gc(long j, int i, int i2);\n\n    private native synchronized int _getField(long j, int i, String str);\n\n    private native synchronized int _getGlobal(long j, String str);\n\n    private native synchronized int _getI(long j, int i, long j2);\n\n    private native synchronized int _getMetaTable(long j, int i);\n\n    private native synchronized Object _getObjectFromUserdata(long j, int i) throws LuaException;\n\n    private native synchronized int _getTable(long j, int i);\n\n    private native synchronized int _getTop(long j);\n\n    private native synchronized String _getUpValue(long j, int i, int i2);\n\n    private native synchronized int _getUserValue(long j, int i);\n\n    private native synchronized void _insert(long j, int i);\n\n    private native synchronized int _isBoolean(long j, int i);\n\n    private native synchronized int _isCFunction(long j, int i);\n\n    private native synchronized int _isFunction(long j, int i);\n\n    private native synchronized int _isInteger(long j, int i);\n\n    private native synchronized boolean _isJavaFunction(long j, int i);\n\n    private native synchronized int _isNil(long j, int i);\n\n    private native synchronized int _isNone(long j, int i);\n\n    private native synchronized int _isNoneOrNil(long j, int i);\n\n    private native synchronized int _isNumber(long j, int i);\n\n    private native synchronized boolean _isObject(long j, int i);\n\n    private native synchronized int _isString(long j, int i);\n\n    private native synchronized int _isTable(long j, int i);\n\n    private native synchronized int _isThread(long j, int i);\n\n    private native synchronized int _isUserdata(long j, int i);\n\n    private native synchronized int _isYieldable(long j);\n\n    private native synchronized int _lessThan(long j, int i, int i2);\n\n    private native synchronized void _newTable(long j);\n\n    private native synchronized long _newstate();\n\n    private native synchronized long _newthread(long j);\n\n    private native synchronized int _next(long j, int i);\n\n    private native synchronized int _objlen(long j, int i);\n\n    private native synchronized void _openBase(long j);\n\n    private native synchronized void _openDebug(long j);\n\n    private native synchronized void _openIo(long j);\n\n    private native synchronized void _openLibs(long j);\n\n    private native synchronized void _openLuajava(long j);\n\n    private native synchronized void _openMath(long j);\n\n    private native synchronized void _openOs(long j);\n\n    private native synchronized void _openPackage(long j);\n\n    private native synchronized void _openString(long j);\n\n    private native synchronized void _openTable(long j);\n\n    private native synchronized int _pcall(long j, int i, int i2, int i3);\n\n    private native synchronized void _pop(long j, int i);\n\n    private native synchronized void _pushBoolean(long j, int i);\n\n    private native synchronized void _pushGlobalTable(long j);\n\n    private native synchronized void _pushInteger(long j, long j2);\n\n    private native synchronized void _pushJavaFunction(long j, JavaFunction javaFunction) throws LuaException;\n\n    private native synchronized void _pushJavaObject(long j, Object obj);\n\n    private native synchronized void _pushNil(long j);\n\n    private native synchronized void _pushNumber(long j, double d);\n\n    private native synchronized void _pushString(long j, String str);\n\n    private native synchronized void _pushString(long j, byte[] bArr, int i);\n\n    private native synchronized void _pushValue(long j, int i);\n\n    private native synchronized int _rawGet(long j, int i);\n\n    private native synchronized int _rawGetI(long j, int i, long j2);\n\n    private native synchronized void _rawSet(long j, int i);\n\n    private native synchronized void _rawSetI(long j, int i, long j2);\n\n    private native synchronized int _rawequal(long j, int i, int i2);\n\n    private native synchronized int _rawlen(long j, int i);\n\n    private native synchronized void _remove(long j, int i);\n\n    private native synchronized void _replace(long j, int i);\n\n    private native synchronized int _resume(long j, long j2, int i);\n\n    private native synchronized void _rotate(long j, int i, int i2);\n\n    private native synchronized void _setField(long j, int i, String str);\n\n    private native synchronized void _setGlobal(long j, String str);\n\n    private native synchronized void _setI(long j, int i, long j2);\n\n    private native synchronized int _setMetaTable(long j, int i);\n\n    private native synchronized void _setTable(long j, int i);\n\n    private native synchronized void _setTop(long j, int i);\n\n    private native synchronized String _setUpValue(long j, int i, int i2);\n\n    private native synchronized void _setUserValue(long j, int i);\n\n    private native synchronized int _status(long j);\n\n    private native synchronized int _strlen(long j, int i);\n\n    private native synchronized int _toBoolean(long j, int i);\n\n    private native synchronized long _toInteger(long j, int i);\n\n    private native synchronized double _toNumber(long j, int i);\n\n    private native synchronized String _toString(long j, int i);\n\n    private native synchronized long _toThread(long j, int i);\n\n    private native synchronized int _type(long j, int i);\n\n    private native synchronized String _typeName(long j, int i);\n\n    private native synchronized void _xmove(long j, long j2, int i);\n\n    private native synchronized int _yield(long j, int i);\n\n    public synchronized void close() {\n        LuaStateFactory.removeLuaState(this.luaState);\n        _close(this.luaState);\n        this.luaState = 0;\n    }\n\n    public synchronized boolean isClosed() {\n        return this.luaState == 0;\n    }\n\n    public long getPointer() {\n        return this.luaState;\n    }\n\n    public void pushContext(LuaContext context) {\n        this.mContext = context;\n    }\n\n    public LuaContext getContext() {\n        return this.mContext;\n    }\n\n    public LuaState newThread() {\n        LuaState l = new LuaState(_newthread(this.luaState));\n        LuaStateFactory.insertLuaState(l);\n        return l;\n    }\n\n    public int getTop() {\n        return _getTop(this.luaState);\n    }\n\n    public void setTop(int idx) {\n        _setTop(this.luaState, idx);\n    }\n\n    public void pushValue(int idx) {\n        _pushValue(this.luaState, idx);\n    }\n\n    public void rotate(int idx, int n) {\n        _rotate(this.luaState, idx, n);\n    }\n\n    public void copy(int fromidx, int toidx) {\n        _copy(this.luaState, fromidx, toidx);\n    }\n\n    public void remove(int idx) {\n        _remove(this.luaState, idx);\n    }\n\n    public void insert(int idx) {\n        _insert(this.luaState, idx);\n    }\n\n    public void replace(int idx) {\n        _replace(this.luaState, idx);\n    }\n\n    public int checkStack(int sz) {\n        return _checkStack(this.luaState, sz);\n    }\n\n    public void xmove(LuaState to, int n) {\n        _xmove(this.luaState, to.luaState, n);\n    }\n\n    public boolean isNumber(int idx) {\n        return _isNumber(this.luaState, idx) != 0;\n    }\n\n    public boolean isInteger(int idx) {\n        return _isInteger(this.luaState, idx) != 0;\n    }\n\n    public boolean isString(int idx) {\n        return _isString(this.luaState, idx) != 0;\n    }\n\n    public boolean isFunction(int idx) {\n        return _isFunction(this.luaState, idx) != 0;\n    }\n\n    public boolean isCFunction(int idx) {\n        return _isCFunction(this.luaState, idx) != 0;\n    }\n\n    public boolean isUserdata(int idx) {\n        return _isUserdata(this.luaState, idx) != 0;\n    }\n\n    public boolean isTable(int idx) {\n        return _isTable(this.luaState, idx) != 0;\n    }\n\n    public boolean isBoolean(int idx) {\n        return _isBoolean(this.luaState, idx) != 0;\n    }\n\n    public boolean isNil(int idx) {\n        return _isNil(this.luaState, idx) != 0;\n    }\n\n    public boolean isThread(int idx) {\n        return _isThread(this.luaState, idx) != 0;\n    }\n\n    public boolean isNone(int idx) {\n        return _isNone(this.luaState, idx) != 0;\n    }\n\n    public boolean isNoneOrNil(int idx) {\n        return _isNoneOrNil(this.luaState, idx) != 0;\n    }\n\n    public int type(int idx) {\n        return _type(this.luaState, idx);\n    }\n\n    public String typeName(int tp) {\n        return _typeName(this.luaState, tp);\n    }\n\n    public int equal(int idx1, int idx2) {\n        return _equal(this.luaState, idx1, idx2);\n    }\n\n    public int compare(int idx1, int idx2, int op) {\n        return _compare(this.luaState, idx1, idx2, op);\n    }\n\n    public int rawequal(int idx1, int idx2) {\n        return _rawequal(this.luaState, idx1, idx2);\n    }\n\n    public int lessThan(int idx1, int idx2) {\n        return _lessThan(this.luaState, idx1, idx2);\n    }\n\n    public double toNumber(int idx) {\n        return _toNumber(this.luaState, idx);\n    }\n\n    public long toInteger(int idx) {\n        return _toInteger(this.luaState, idx);\n    }\n\n    public boolean toBoolean(int idx) {\n        return _toBoolean(this.luaState, idx) != 0;\n    }\n\n    public String toString(int idx) {\n        return _toString(this.luaState, idx);\n    }\n\n    public int strLen(int idx) {\n        return _strlen(this.luaState, idx);\n    }\n\n    public int objLen(int idx) {\n        return _objlen(this.luaState, idx);\n    }\n\n    public int rawLen(int idx) {\n        return _rawlen(this.luaState, idx);\n    }\n\n    public LuaState toThread(int idx) {\n        return new LuaState(_toThread(this.luaState, idx));\n    }\n\n    public void pushNil() {\n        _pushNil(this.luaState);\n    }\n\n    public void pushNumber(double db) {\n        _pushNumber(this.luaState, db);\n    }\n\n    public void pushInteger(long integer) {\n        _pushInteger(this.luaState, integer);\n    }\n\n    public void pushString(String str) {\n        if (str == null) {\n            _pushNil(this.luaState);\n        } else {\n            _pushString(this.luaState, str);\n        }\n    }\n\n    public void pushString(byte[] bytes) {\n        if (bytes == null) {\n            _pushNil(this.luaState);\n        } else {\n            _pushString(this.luaState, bytes, bytes.length);\n        }\n    }\n\n    public void pushBoolean(boolean bool) {\n        _pushBoolean(this.luaState, bool ? 1 : 0);\n    }\n\n    public int getTable(int idx) {\n        return _getTable(this.luaState, idx);\n    }\n\n    public int getField(int idx, String k) {\n        return _getField(this.luaState, idx, k);\n    }\n\n    public int getI(int idx, long n) {\n        return _getI(this.luaState, idx, n);\n    }\n\n    public int rawGet(int idx) {\n        return _rawGet(this.luaState, idx);\n    }\n\n    public int rawGetI(int idx, long n) {\n        return _rawGetI(this.luaState, idx, n);\n    }\n\n    public void createTable(int narr, int nrec) {\n        _createTable(this.luaState, narr, nrec);\n    }\n\n    public void newTable() {\n        _newTable(this.luaState);\n    }\n\n    public int getMetaTable(int idx) {\n        return _getMetaTable(this.luaState, idx);\n    }\n\n    public int getUserValue(int idx) {\n        return _getUserValue(this.luaState, idx);\n    }\n\n    public void setTable(int idx) {\n        _setTable(this.luaState, idx);\n    }\n\n    public void setField(int idx, String k) {\n        _setField(this.luaState, idx, k);\n    }\n\n    public void setI(int idx, long n) {\n        _setI(this.luaState, idx, n);\n    }\n\n    public void rawSet(int idx) {\n        _rawSet(this.luaState, idx);\n    }\n\n    public void rawSetI(int idx, long n) {\n        _rawSetI(this.luaState, idx, n);\n    }\n\n    public int setMetaTable(int idx) {\n        return _setMetaTable(this.luaState, idx);\n    }\n\n    public void setUserValue(int idx) {\n        _setUserValue(this.luaState, idx);\n    }\n\n    public void call(int nArgs, int nResults) {\n        _call(this.luaState, nArgs, nResults);\n    }\n\n    public int pcall(int nArgs, int nResults, int errFunc) {\n        return _pcall(this.luaState, nArgs, nResults, errFunc);\n    }\n\n    public int yield(int nResults) {\n        return _yield(this.luaState, nResults);\n    }\n\n    public int resume(LuaState from, int nArgs) {\n        return _resume(this.luaState, from.getPointer(), nArgs);\n    }\n\n    public int status() {\n        return _status(this.luaState);\n    }\n\n    public int isYieldable() {\n        return _isYieldable(this.luaState);\n    }\n\n    public int gc(int what, int data) {\n        return _gc(this.luaState, what, data);\n    }\n\n    public int next(int idx) {\n        return _next(this.luaState, idx);\n    }\n\n    public int error() {\n        return _error(this.luaState);\n    }\n\n    public void concat(int n) {\n        _concat(this.luaState, n);\n    }\n\n    public int LdoFile(String fileName) {\n        return _LdoFile(this.luaState, fileName);\n    }\n\n    public int LdoString(String str) {\n        return _LdoString(this.luaState, str);\n    }\n\n    public int LgetMetaField(int obj, String e) {\n        return _LgetMetaField(this.luaState, obj, e);\n    }\n\n    public int LcallMeta(int obj, String e) {\n        return _LcallMeta(this.luaState, obj, e);\n    }\n\n    public int LargError(int numArg, String extraMsg) {\n        return _LargError(this.luaState, numArg, extraMsg);\n    }\n\n    public String LcheckString(int numArg) {\n        return _LcheckString(this.luaState, numArg);\n    }\n\n    public String LoptString(int numArg, String def) {\n        return _LoptString(this.luaState, numArg, def);\n    }\n\n    public double LcheckNumber(int numArg) {\n        return _LcheckNumber(this.luaState, numArg);\n    }\n\n    public double LoptNumber(int numArg, double def) {\n        return _LoptNumber(this.luaState, numArg, def);\n    }\n\n    public int LcheckInteger(int numArg) {\n        return _LcheckInteger(this.luaState, numArg);\n    }\n\n    public int LoptInteger(int numArg, int def) {\n        return _LoptInteger(this.luaState, numArg, def);\n    }\n\n    public void LcheckStack(int sz, String msg) {\n        _LcheckStack(this.luaState, sz, msg);\n    }\n\n    public void LcheckType(int nArg, int t) {\n        _LcheckType(this.luaState, nArg, t);\n    }\n\n    public void LcheckAny(int nArg) {\n        _LcheckAny(this.luaState, nArg);\n    }\n\n    public int LnewMetatable(String tName) {\n        return _LnewMetatable(this.luaState, tName);\n    }\n\n    public void LgetMetatable(String tName) {\n        _LgetMetatable(this.luaState, tName);\n    }\n\n    public void Lwhere(int lvl) {\n        _Lwhere(this.luaState, lvl);\n    }\n\n    public int Lref(int t) {\n        return _Lref(this.luaState, t);\n    }\n\n    public void LunRef(int t, int ref) {\n        _LunRef(this.luaState, t, ref);\n    }\n\n    public int LloadFile(String fileName) {\n        return _LloadFile(this.luaState, fileName);\n    }\n\n    public int LloadString(String s) {\n        return _LloadString(this.luaState, s);\n    }\n\n    public int LloadBuffer(byte[] buff, String name) {\n        return _LloadBuffer(this.luaState, buff, (long) buff.length, name);\n    }\n\n    public String Lgsub(String s, String p, String r) {\n        return _Lgsub(this.luaState, s, p, r);\n    }\n\n    public String getUpValue(int funcindex, int n) {\n        return _getUpValue(this.luaState, funcindex, n);\n    }\n\n    public String setUpValue(int funcindex, int n) {\n        return _setUpValue(this.luaState, funcindex, n);\n    }\n\n    public byte[] dump(int funcindex) {\n        return _dump(this.luaState, funcindex);\n    }\n\n    public void pop(int n) {\n        _pop(this.luaState, n);\n    }\n\n    public synchronized void pushGlobalTable() {\n        _pushGlobalTable(this.luaState);\n    }\n\n    public synchronized int getGlobal(String global) {\n        return _getGlobal(this.luaState, global);\n    }\n\n    public synchronized void setGlobal(String name) {\n        _setGlobal(this.luaState, name);\n    }\n\n    public void openBase() {\n        _openBase(this.luaState);\n    }\n\n    public void openTable() {\n        _openTable(this.luaState);\n    }\n\n    public void openIo() {\n        _openIo(this.luaState);\n    }\n\n    public void openOs() {\n        _openOs(this.luaState);\n    }\n\n    public void openString() {\n        _openString(this.luaState);\n    }\n\n    public void openMath() {\n        _openMath(this.luaState);\n    }\n\n    public void openDebug() {\n        _openDebug(this.luaState);\n    }\n\n    public void openPackage() {\n        _openPackage(this.luaState);\n    }\n\n    public void openLibs() {\n        _openLibs(this.luaState);\n        _openLuajava(this.luaState);\n        pushPrimitive();\n    }\n\n    public void openLuajava() {\n        _openLuajava(this.luaState);\n        pushPrimitive();\n    }\n\n    public Object getObjectFromUserdata(int idx) throws LuaException {\n        return _getObjectFromUserdata(this.luaState, idx);\n    }\n\n    public boolean isObject(int idx) {\n        return _isObject(this.luaState, idx);\n    }\n\n    public void pushJavaObject(Object obj) {\n        _pushJavaObject(this.luaState, obj);\n    }\n\n    public void pushJavaFunction(JavaFunction func) throws LuaException {\n        _pushJavaFunction(this.luaState, func);\n    }\n\n    public boolean isJavaFunction(int idx) {\n        return _isJavaFunction(this.luaState, idx);\n    }\n\n    public void pushObjectValue(Object obj) throws LuaException {\n        if (obj == null) {\n            pushNil();\n        } else if (obj instanceof Boolean) {\n            pushBoolean(((Boolean) obj).booleanValue());\n        } else if (obj instanceof Long) {\n            pushInteger(((Long) obj).longValue());\n        } else if (obj instanceof Integer) {\n            pushInteger((long) ((Integer) obj).intValue());\n        } else if (obj instanceof Short) {\n            pushInteger((long) ((Short) obj).shortValue());\n        } else if (obj instanceof Character) {\n            pushInteger((long) ((Character) obj).charValue());\n        } else if (obj instanceof Byte) {\n            pushInteger((long) ((Byte) obj).byteValue());\n        } else if (obj instanceof Float) {\n            pushNumber((double) ((Float) obj).floatValue());\n        } else if (obj instanceof Double) {\n            pushNumber(((Double) obj).doubleValue());\n        } else if (obj instanceof String) {\n            pushString((String) obj);\n        } else if (obj instanceof JavaFunction) {\n            pushJavaFunction((JavaFunction) obj);\n        } else if (obj instanceof LuaObject) {\n            LuaObject ref = (LuaObject) obj;\n            if (ref.getLuaState() == this) {\n                ref.push();\n            } else {\n                pushJavaObject(ref);\n            }\n        } else {\n            pushJavaObject(obj);\n        }\n    }\n\n    public synchronized Object toJavaObject(int idx) throws LuaException {\n        Object obj;\n        obj = null;\n        if (isBoolean(idx)) {\n            obj = Boolean.valueOf(toBoolean(idx));\n        } else if (type(idx) == 4) {\n            obj = toString(idx);\n        } else if (isFunction(idx)) {\n            obj = getLuaObject(idx);\n        } else if (isTable(idx)) {\n            obj = getLuaObject(idx);\n        } else if (type(idx) == 3) {\n            if (isInteger(idx)) {\n                obj = Long.valueOf(toInteger(idx));\n            } else {\n                obj = Double.valueOf(toNumber(idx));\n            }\n        } else if (isUserdata(idx)) {\n            if (isObject(idx)) {\n                obj = getObjectFromUserdata(idx);\n            } else {\n                obj = getLuaObject(idx);\n            }\n        } else if (isNil(idx)) {\n            obj = null;\n        }\n        return obj;\n    }\n\n    public LuaObject getLuaObject(String globalName) {\n        pushGlobalTable();\n        pushString(globalName);\n        rawGet(-2);\n        LuaObject obj = getLuaObject(-1);\n        pop(2);\n        return obj;\n    }\n\n    public LuaObject getLuaObject(LuaObject parent, String name) throws LuaException {\n        return new LuaObject(parent, name);\n    }\n\n    public LuaObject getLuaObject(LuaObject parent, Number name) throws LuaException {\n        return new LuaObject(parent, name);\n    }\n\n    public LuaObject getLuaObject(LuaObject parent, LuaObject name) throws LuaException {\n        if (parent.getLuaState().getPointer() == this.luaState && parent.getLuaState().getPointer() == name.getLuaState().getPointer()) {\n            return new LuaObject(parent, name);\n        }\n        throw new LuaException(\"Object must have the same LuaState as the parent!\");\n    }\n\n    public LuaObject getLuaObject(int index) {\n        if (isFunction(index)) {\n            return new LuaFunction(this, index);\n        }\n        if (isTable(index)) {\n            return new LuaTable(this, index);\n        }\n        return new LuaObject(this, index);\n    }\n\n    public void pushPrimitive() {\n        pushJavaObject(Boolean.TYPE);\n        setGlobal(\"boolean\");\n        pushJavaObject(Byte.TYPE);\n        setGlobal(\"byte\");\n        pushJavaObject(Character.TYPE);\n        setGlobal(\"char\");\n        pushJavaObject(Short.TYPE);\n        setGlobal(\"short\");\n        pushJavaObject(Integer.TYPE);\n        setGlobal(\"int\");\n        pushJavaObject(Long.TYPE);\n        setGlobal(\"long\");\n        pushJavaObject(Float.TYPE);\n        setGlobal(\"float\");\n        pushJavaObject(Double.TYPE);\n        setGlobal(\"double\");\n    }\n}"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/LuaStateFactory.java",
    "content": "/*\n * $Id: LuaStateFactory.java,v 1.4 2006/12/22 14:06:40 thiago Exp $\n * Copyright (C) 2003-2007 Kepler Project.\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\npackage com.luajava;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * This class is responsible for instantiating new LuaStates.\n * When a new LuaState is instantiated it is put into a List\n * and an index is returned. This index is registred in Lua\n * and it is used to find the right LuaState when lua calls\n * a Java Function.\n *\n * @author Thiago Ponte\n */\npublic final class LuaStateFactory {\n    /**\n     * Array with all luaState's instances\n     */\n    private static final Map<Long, LuaState> states = new HashMap<Long, LuaState>();\n\n    /**\n     * Non-public constructor.\n     */\n    private LuaStateFactory() {\n    }\n\n    /**\n     * Method that creates a new instance of LuaState\n     *\n     * @return LuaState\n     */\n    public synchronized static LuaState newLuaState() {\n        LuaState L = new LuaState();\n\n        states.put(L.getPointer(), L);\n\n        return L;\n    }\n\n    /**\n     * Returns a existing instance of LuaState\n     *\n     * @param index\n     * @return LuaState\n     */\n    public synchronized static LuaState getExistingState(long index) {\n        LuaState l = states.get(index);\n        if (l == null) {\n            l = new LuaState(index);\n            states.put(index, l);\n        }\n        return l;\n    }\n\n    /**\n     * Receives a existing LuaState and checks if it exists in the states list.\n     * If it doesn't exist adds it to the list.\n     *\n     * @param L\n     * @return int\n     */\n    public synchronized static long insertLuaState(LuaState L) {\n        states.put(L.getPointer(), L);\n\n        return L.getPointer();\n    }\n\n    /**\n     * removes the luaState from the states list\n     *\n     * @param idx\n     */\n    public synchronized static void removeLuaState(long idx) {\n        states.put(idx, null);\n    }\n\n\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/java/com/luajava/LuaTable.java",
    "content": "package com.luajava;\n\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class LuaTable<K, V> extends LuaObject implements Map<K, V> {\n\n    protected LuaTable(LuaState L, String globalName) {\n        super(L, globalName);\n    }\n\n    protected LuaTable(LuaState L, int index) {\n        super(L, index);\n    }\n\n    public LuaTable(LuaState L) {\n        super(L);\n        L.newTable();\n        registerValue(-1);\n    }\n\n    @Override\n    public void clear() {\n        push();\n        L.pushNil();\n        while (L.next(-2) != 0) {\n            L.pop(1);\n            L.pushValue(-1);\n            L.pushNil();\n            L.setTable(-4);\n        }\n        L.pop(1);\n    }\n\n    @Override\n    public boolean containsKey(Object key) {\n        boolean b = false;\n        push();\n        try {\n            L.pushObjectValue(key);\n            b = L.getTable(-2) == LuaState.LUA_TNIL;\n            L.pop(1);\n        } catch (LuaException e) {\n            return false;\n        }\n        L.pop(1);\n        return b;\n    }\n\n    @Override\n    public boolean containsValue(Object value) {\n        return false;\n    }\n\n    @Override\n    public Set<Entry<K, V>> entrySet() {\n        HashSet<Entry<K, V>> sets = new HashSet<Entry<K, V>>();\n        push();\n        L.pushNil();\n        while (L.next(-2) != 0) {\n            try {\n                sets.add(new LuaEntry<K, V>((K) L.toJavaObject(-2), (V) L.toJavaObject(-1)));\n            } catch (LuaException e) {\n            }\n            L.pop(1);\n        }\n        L.pop(1);\n        return sets;\n    }\n\n    @Override\n    public V get(Object key) {\n        push();\n        V obj = null;\n        try {\n            L.pushObjectValue(key);\n            L.getTable(-2);\n            obj = (V) L.toJavaObject(-1);\n            L.pop(1);\n        } catch (LuaException e) {\n        }\n        L.pop(1);\n        return obj;\n    }\n\n    @Override\n    public boolean isEmpty() {\n        push();\n        L.pushNil();\n        boolean b = L.next(-2) == 0;\n        if (b)\n            L.pop(1);\n        else\n            L.pop(3);\n        return b;\n    }\n\n    @Override\n    public Set<K> keySet() {\n        HashSet<K> sets = new HashSet<K>();\n        push();\n        L.pushNil();\n        while (L.next(-2) != 0) {\n            try {\n                sets.add((K) L.toJavaObject(-2));\n            } catch (LuaException e) {\n            }\n            L.pop(1);\n        }\n        L.pop(1);\n        return sets;\n    }\n\n    @Override\n    public V put(K key, V value) {\n        push();\n        try {\n            L.pushObjectValue(key);\n            L.pushObjectValue(value);\n            L.setTable(-3);\n        } catch (LuaException e) {\n        }\n        L.pop(1);\n        return null;\n    }\n\n    @Override\n    public void putAll(Map p1) {\n    }\n\n    @Override\n    public V remove(Object key) {\n        push();\n        try {\n            L.pushObjectValue(key);\n            L.setTable(-2);\n        } catch (LuaException e) {\n        }\n        L.pop(1);\n        return null;\n    }\n\n    public boolean isList() {\n        push();\n        int len = L.rawLen(-1);\n        if (len != 0) {\n            pop();\n            return true;\n        }\n        L.pushNil();\n        boolean b = L.next(-2) == 0;\n        if (b)\n            L.pop(1);\n        else\n            L.pop(3);\n        return b;\n    }\n\n    public int length() {\n        push();\n        int len = L.rawLen(-1);\n        pop();\n        return len;\n    }\n\n    @Override\n    public int size() {\n        int n = 0;\n        push();\n        L.pushNil();\n        while (L.next(-2) != 0) {\n            n++;\n            L.pop(1);\n        }\n        L.pop(1);\n        return n;\n    }\n\n    @Override\n    public Collection values() {\n        return null;\n    }\n\n    public static class LuaEntry<K, V> implements Entry<K, V> {\n\n        private K mKey;\n\n        private V mValue;\n\n        public LuaEntry(K k, V v) {\n            mKey = k;\n            mValue = v;\n        }\n\n        @Override\n        public K getKey() {\n            return mKey;\n        }\n\n        @Override\n        public V getValue() {\n            return mValue;\n        }\n\n        public V setValue(V value) {\n            V old = mValue;\n            mValue = value;\n            return old;\n        }\n    }\n}\n"
  },
  {
    "path": "hydrogen-library/src/main/res/drawable/bg_circle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"false\">\n        <shape android:shape=\"oval\">\n            <solid android:color=\"#2a000000\"/>\n        </shape>\n    </item>\n</selector>"
  },
  {
    "path": "hydrogen-library/src/main/res/drawable/bg_rect_radius.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"false\">\n        <shape android:shape=\"rectangle\">\n            <corners android:radius=\"40dp\"/>\n            <solid android:color=\"#11222222\"/>\n        </shape>\n    </item>\n</selector>"
  },
  {
    "path": "hydrogen-library/src/main/res/drawable/ic_loading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       android:shape=\"rectangle\">\n    <solid android:color=\"#ebf0f2\"/>\n\n</shape>"
  },
  {
    "path": "hydrogen-library/src/main/res/drawable/layout_selector_tran.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:enterFadeDuration=\"100\"\n    android:exitFadeDuration=\"100\">\n    <item android:state_pressed=\"true\">\n        <color android:color=\"#19000000\"/>\n    </item>\n    <item>\n        <color android:color=\"#00ffffff\"/>\n    </item>\n</selector>\n"
  },
  {
    "path": "hydrogen-library/src/main/res/drawable/loading_shap.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<rotate xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:fromDegrees=\"0\"\n        android:pivotX=\"50%\"\n        android:pivotY=\"50%\"\n        android:toDegrees=\"360\">\n    <bitmap\n        android:antialias=\"true\"\n        android:filter=\"true\"\n        android:src=\"@drawable/progress\"></bitmap>\n</rotate>"
  },
  {
    "path": "hydrogen-library/src/main/res/drawable/shadow_line_bottom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <gradient\n        android:angle=\"90\"\n        android:centerColor=\"#06000000\"\n        android:endColor=\"#00000000\"\n        android:startColor=\"#11000000\"\n        android:type=\"linear\"/>\n    <size android:height=\"7px\"/>\n</shape>"
  },
  {
    "path": "hydrogen-library/src/main/res/drawable/shadow_line_top.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <gradient\n        android:angle=\"-90\"\n        android:centerColor=\"#09000000\"\n        android:endColor=\"#00000000\"\n        android:startColor=\"#22000000\"\n        android:type=\"linear\"/>\n    <size android:height=\"7px\"/>\n</shape>"
  },
  {
    "path": "hydrogen-library/src/main/res/layout/activity_lua.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.widget.DrawerLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/layout_drawer\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <FrameLayout\n        android:id=\"@+id/main\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"/>\n\n    <FrameLayout\n        android:id=\"@+id/menu\"\n        android:layout_width=\"80dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"right\"\n        android:background=\"#11FFFFFF\"/>\n\n</android.support.v4.widget.DrawerLayout>"
  },
  {
    "path": "hydrogen-library/src/main/res/layout/activity_picture.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<androlua.widget.picture.ElasticDragDismissFrameLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/dragdismiss_drag_dismiss_layout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    app:layout_behavior=\"androlua.widget.picture.SwipeDismissBehavior\">\n\n    <android.support.v4.widget.NestedScrollView\n        android:id=\"@+id/dragdismiss_scroll_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:fillViewport=\"true\"\n        android:overScrollMode=\"never\">\n\n\n        <android.support.v4.view.ViewPager\n            android:id=\"@+id/viewpager\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n        </android.support.v4.view.ViewPager>\n\n\n    </android.support.v4.widget.NestedScrollView>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"56dp\"\n        android:layout_gravity=\"bottom\"\n        android:alpha=\"0.7\">\n\n        <TextView\n            android:id=\"@+id/tv_count\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"center_vertical\"\n            android:paddingLeft=\"16dp\"\n            tools:text=\"2/333\"\n            android:textColor=\"#ffffff\"\n            android:textSize=\"18sp\"/>\n\n        <ImageView\n            android:id=\"@+id/iv_download\"\n            android:layout_width=\"56dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_alignParentRight=\"true\"\n            android:background=\"@drawable/layout_selector_tran\"\n            android:padding=\"16dp\"\n            android:src=\"@drawable/ic_download\"/>\n\n        <ImageView\n            android:id=\"@+id/iv_share\"\n            android:layout_width=\"56dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_toLeftOf=\"@+id/iv_download\"\n            android:background=\"@drawable/layout_selector_tran\"\n            android:padding=\"18dp\"\n            android:scaleType=\"centerInside\"\n            android:src=\"@drawable/ic_share\"/>\n    </RelativeLayout>\n</androlua.widget.picture.ElasticDragDismissFrameLayout>\n"
  },
  {
    "path": "hydrogen-library/src/main/res/layout/activity_video.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"#000000\"\n    android:orientation=\"vertical\">\n\n    <cn.jzvd.JZVideoPlayerStandard\n        android:id=\"@+id/videoplayer\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"202.5dp\"\n        android:layout_gravity=\"center\" />\n\n</FrameLayout>"
  },
  {
    "path": "hydrogen-library/src/main/res/layout/activity_webview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\"\n              android:orientation=\"vertical\">\n\n    <androlua.widget.statusbar.StatusBarView\n        android:id=\"@+id/view_statusbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <RelativeLayout\n        android:id=\"@+id/layout_toolbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"48dp\"\n        android:background=\"#f00\"\n        android:focusable=\"true\"\n        android:focusableInTouchMode=\"true\"\n        android:orientation=\"horizontal\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginBottom=\"10dp\"\n            android:layout_marginLeft=\"8dp\"\n            android:layout_marginTop=\"10dp\"\n            android:layout_toLeftOf=\"@+id/iv_more\"\n            android:background=\"@drawable/bg_rect_radius\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"horizontal\">\n\n            <EditText\n                android:id=\"@+id/et_url\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1\"\n                android:background=\"@null\"\n                android:ellipsize=\"end\"\n                android:lines=\"1\"\n                android:maxLines=\"1\"\n                android:paddingLeft=\"12dp\"\n                android:singleLine=\"true\"\n                android:text=\"为哦波\"\n                android:textColor=\"#aaffffff\"\n                android:textColorHint=\"#44ffffff\"\n                android:textSize=\"13sp\"/>\n\n            <FrameLayout\n                android:layout_width=\"30dp\"\n                android:layout_height=\"30dp\">\n\n                <android.support.v4.widget.ContentLoadingProgressBar\n                    android:id=\"@+id/loading\"\n                    style=\"?android:attr/progressBarStyleSmall\"\n                    android:layout_width=\"14dp\"\n                    android:layout_height=\"14dp\"\n                    android:layout_gravity=\"center\"\n                    android:alpha=\"0.6\"\n                    android:indeterminateDrawable=\"@drawable/loading_shap\"/>\n\n                <ImageView\n                    android:id=\"@+id/iv_refresh\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:alpha=\"0.4\"\n                    android:scaleType=\"centerInside\"\n                    android:src=\"@drawable/ic_refresh\"\n                    android:visibility=\"gone\"/>\n            </FrameLayout>\n\n        </LinearLayout>\n\n        <ImageView\n            android:id=\"@+id/iv_more\"\n            android:background=\"@drawable/layout_selector_tran\"\n            android:layout_width=\"32dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:padding=\"4dp\"\n            android:src=\"@drawable/ic_more\"/>\n    </RelativeLayout>\n\n    <androlua.widget.statusbar.FixInsetsFrameLayout\n        android:fitsSystemWindows=\"true\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <androlua.LuaWebView\n            android:id=\"@+id/webview\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"/>\n    </androlua.widget.statusbar.FixInsetsFrameLayout>\n</LinearLayout>"
  },
  {
    "path": "hydrogen-library/src/main/res/layout/dialog_add_shortcut.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\"\n              android:gravity=\"bottom\"\n              android:orientation=\"horizontal\"\n              android:padding=\"16dp\">\n\n    <ImageView\n        android:id=\"@+id/icon\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:src=\"@mipmap/ic_launcher\"/>\n\n    <EditText\n        android:id=\"@+id/name\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"8dp\"/>\n\n</LinearLayout>"
  },
  {
    "path": "hydrogen-library/src/main/res/layout/dialog_input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <EditText\n        android:id=\"@+id/et\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n</LinearLayout>"
  },
  {
    "path": "hydrogen-library/src/main/res/layout/fragment_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\"\n              android:gravity=\"center\"\n              android:orientation=\"vertical\">\n\n    <ImageView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"56dp\"\n        android:background=\"@drawable/layout_selector_tran\"\n        android:contentDescription=\"收藏\"\n        android:scaleType=\"centerInside\"\n        android:src=\"@drawable/ic_star_border_white_24dp\"\n        android:visibility=\"gone\"/>\n\n    <ImageView\n        android:id=\"@+id/add_shortcut\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"56dp\"\n        android:background=\"@drawable/layout_selector_tran\"\n        android:contentDescription=\"添加快捷\"\n        android:scaleType=\"centerInside\"\n        android:src=\"@drawable/ic_launch_white_24dp\"/>\n</LinearLayout>"
  },
  {
    "path": "hydrogen-library/src/main/res/layout/item_pager_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n             android:layout_width=\"match_parent\"\n             android:layout_height=\"match_parent\"\n             android:orientation=\"vertical\">\n\n    <ImageView\n        android:id=\"@+id/iv_small\"\n        android:layout_gravity=\"center\"\n        android:layout_width=\"match_parent\"\n        android:visibility=\"gone\"\n        android:layout_height=\"match_parent\"/>\n\n    <com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView\n        android:id=\"@+id/iv_big\"\n        android:layout_gravity=\"center\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"/>\n\n    <ProgressBar\n        android:id=\"@+id/loading\"\n        android:layout_width=\"32dp\"\n        android:layout_height=\"32dp\"\n        android:layout_gravity=\"center\"/>\n\n</FrameLayout>"
  },
  {
    "path": "hydrogen-library/src/main/res/raw/keep.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:keep=\"@drawable/*,@drawable-xxhdpi/*,@drawable-xxxhdpi/*\"/>"
  },
  {
    "path": "hydrogen-library/src/main/res/values/attrs_elastic_drag_dismiss_frame_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright 2015 Google Inc.\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n       http://www.apache.org/licenses/LICENSE-2.0\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n\n<resources>\n\n    <declare-styleable name=\"ElasticDragDismissFrameLayout\">\n        <attr name=\"dragDismissDistance\" format=\"dimension\" />\n        <attr name=\"dragDismissFraction\" format=\"float\" />\n        <attr name=\"dragDismissScale\" format=\"float\" />\n        <attr name=\"dragElasticity\" format=\"float\" />\n    </declare-styleable>\n\n</resources>"
  },
  {
    "path": "hydrogen-library/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "hydrogen-library/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">LuaJAndroid</string>\n</resources>\n"
  },
  {
    "path": "hydrogen-library/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "hydrogen-library/src/test/java/pub/hanks/luajandroid/ExampleUnitTest.java",
    "content": "package pub.hanks.luajandroid;\n\nimport org.junit.Test;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.FilenameFilter;\nimport java.io.IOException;\nimport java.util.zip.Adler32;\nimport java.util.zip.CheckedOutputStream;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\nimport static org.junit.Assert.assertEquals;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void testAdler32() throws Exception {\n        String target = \"ajavachecksum.zip\";\n\n        FileOutputStream fos = new FileOutputStream(target);\n\n        //使用Adler32算法创建CheckedOutputStream校验输出流\n        CheckedOutputStream checksum = new CheckedOutputStream(fos, new Adler32());\n        ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(checksum));\n\n        int size = 0;\n        byte[] buffer = new byte[1024];\n\n        //\n        // Get all text files on the working folder.\n        //通过FilenameFilter取得所有txt文件\n        File dir = new File(\".\");\n        String[] files = dir.list(new FilenameFilter() {\n            public boolean accept(File dir, String name) {\n                if (name.endsWith(\".txt\")) {\n                    return true;\n                } else {\n                    return false;\n                }\n            }\n        });\n\n        //压缩成ajavachecksum.zip\n        for (int i = 0; i < files.length; i++) {\n            System.out.println(\"压缩中...: \" + files[i]);\n\n            FileInputStream fis = new FileInputStream(files[i]);\n            ZipEntry zipEntry = new ZipEntry(files[i]);\n            zos.putNextEntry(zipEntry);\n\n            while ((size = fis.read(buffer, 0, buffer.length)) > 0) {\n                zos.write(buffer, 0, size);\n            }\n\n            zos.flush();\n            zos.closeEntry();\n            fis.close();\n        }\n\n        zos.flush();\n        zos.close();\n\n        System.out.println(\" 校验码  : \" + checksum.getChecksum().getValue());\n\n    }\n\n    @Test\n    public void testStartWith(){\n        System.out.println(\"asdas\".startsWith(\"[a-z]\"));\n    }\n}"
  },
  {
    "path": "hydrogen-library/src/test/lua/a/aa.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/12\n-- Time: 15:07\n-- \nlocal me = require \"b.ba\"\n\nprint(me.name)\n"
  },
  {
    "path": "hydrogen-library/src/test/lua/a.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/12\n-- Time: 15:06\n--\nlocal me = {\n    name = \"hanks\"\n}\n\nrequire(\"c.json\")\n\nprint(json.decode(''))\nreturn me\n"
  },
  {
    "path": "hydrogen-library/src/test/lua/b/ba.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/12\n-- Time: 15:07\n--\n\nreturn {\n    name = \"from be\"\n}\n"
  },
  {
    "path": "hydrogen-library/src/test/lua/c/json.lua",
    "content": "module('json')\n\nfunction decode(text)\n    return { name = 'hhhhha' }\nend"
  },
  {
    "path": "lua/163news/activity_news_detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nlocal uihelper = require \"uihelper\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#ff3333\",\n    {\n        LinearLayout,\n        orientation = \"horizontal\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#ff3333\",\n        gravity = \"center_vertical\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginLeft = \"8dp\",\n            scaleType = \"centerInside\",\n            src = \"@drawable/ic_menu_back\",\n        },\n        {\n            TextView,\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            singleLine = true,\n            textIsSelectable = true,\n            ellipsize = \"end\",\n            id = \"tv_title\",\n            gravity = \"center_vertical\",\n            paddingLeft = \"8dp\",\n            textColor = \"#ffffff\",\n            textSize = \"16sp\",\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            LuaWebView,\n            id = \"webview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        },\n        {\n            FrameLayout,\n            layout_gravity = 85,\n            layout_width = \"100dp\",\n            layout_height = \"100dp\",\n            id = \"layout_content\",\n        }\n    }\n}\n\nlocal css = [[\n    video{width:100%} article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-webkit-text-size-adjust:100%}body{font-family:'Helvetica Neue',Helvetica,Arial,Sans-serif;background:#fff;padding-top:0;margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0}h1,h2,h3,h4,h5,h6{font-size:16px}abbr[title]{border-bottom:1px dotted}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:\\201C\\201D\\2018\\2019}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0;vertical-align:middle;color:transparent;font-size:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}table{border-collapse:collapse;border-spacing:0;overflow:hidden}a{text-decoration:none}blockquote{border-left:3px solid #d0e5f2;font-style:normal;display:block;vertical-align:baseline;font-size:100%;margin:.5em 0;padding:0 0 0 1em}ul,ol{padding-left:20px}.content{color:#444;line-height:1.6em;font-size:16px;margin:16px}.content img{max-width:100%;display:block;margin:30px auto}.content img+img{margin-top:15px}.content img[src*=\"zhihu.com/equation\"]{display:inline-block;margin:0 3px}.content a{color:#259}.content a:hover{text-decoration:underline}\n]]\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html>\n<head>\n    <title></title>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,user-scalable=no,viewport-fit=cover\">\n    <style type=\"text/css\"> %s </style>\n</head>\n<body>\n<div class=\"content\"> %s </div>\n<script type=\"text/javascript\">\nfunction openImgActivity(a,b){var c=JSON.stringify({currentIndex:b,uris:a});var d=\"hydrogen://pub.hydrogen.android?action=open_img&data=\"+c;var e=document.createElement(\"iframe\");e.src=d;e.style.display=\"none\";document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},2000)}function init(){var a=document.querySelectorAll(\".content img\");for(var b=0;b<a.length;b++){a[b].addEventListener(\"click\",function(g){var e=g.target||g.srcElement;var c=[];var d=0;var h=document.querySelectorAll(\".content img\");for(var f=0;f<h.length;f++){c[f]=h[f].getAttribute(\"src\");if(e.getAttribute(\"src\").indexOf(c[f])!=-1){d=f}}openImgActivity(c,d)})}}init();\n</script>\n</body>\n</html>\n]]\nlocal function getData(url)\n    url = url:gsub('.html', '_0.html')\n    LuaHttp.request({ url = url }, function(error, code, body)\n        print(url)\n        local content = string.match(body, '<article.->(.-)</article>')\n        local data = string.format(htmlTemplate, css, content)\n        data = data:gsub('src=\"//', 'src=\"http://'):gsub('data[-]src=\"', 'src=\"')\n        uihelper.runOnUiThread(activity, function()\n            webview.loadData(data, \"text/html; charset=UTF-8\", nil)\n        end)\n    end)\nend\n\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    back.onClick = function()\n        activity.finish()\n    end\n    local url = activity.getIntent().getStringExtra('url')\n    tv_title.setText(url)\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    getData(url)\nend\n\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend\n"
  },
  {
    "path": "lua/163news/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\n\n\nlocal function getData(params, data, adapter, fragment, swipe_layout, reload)\n\n    -- http://3g.163.com/touch/jsonp/sy/recommend/30-10.html?hasad=1&miss=25&refresh=A&offset=0&size=10&callback=syrec3\n    -- http://3g.163.com/touch/jsonp/sy/recommend/40-10.html?hasad=1&miss=25&refresh=A&offset=0&size=10&callback=syrec4\n    -- http://3g.163.com/touch/reconstruct/article/list/BBM54PGAwangning/10-10.html\n    -- http://3g.163.com/touch/reconstruct/article/list/BBM54PGAwangning/20-10.html\n    -- http://3g.163.com/touch/reconstruct/article/list/BCR1UC1Qwangning/0-10.html\n\n    local url = string.format('http://3g.163.com/touch/reconstruct/article/list/%s/%d-10.html', params.rid, params.page * 10)\n    print(url)\n\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then return end\n        body = body:sub(10, #body - 1)\n        local arr = JSON.decode(body)[params.rid]\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                for k, _ in pairs(date) do data[k] = nil end\n            end\n            for i = 1, #arr do\n                data[#data + 1] = arr[i]\n            end\n            params.page = params.page + 1\n            adapter.notifyDataSetChanged()\n            swipe_layout.setRefreshing(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, item)\n    local activity = fragment.getActivity()\n    if item == nil or item.url == nil then\n        activity.toast('没有 url 可以打开')\n        return\n    end\n    if not item.url:find('^http://') then\n        WebViewActivity.start(activity, item.skipURL, 0xFFff3333)\n        return\n    else\n        local activity = fragment.getActivity()\n        local intent = Intent(activity, LuaActivity)\n        intent.putExtra(\"luaPath\", '163news/activity_news_detail.lua')\n        intent.putExtra(\"url\", item.url)\n        activity.startActivity(intent)\n    end\nend\n\nlocal function dateStr(d)\n    if type(d) == 'string' then\n        local Y, M, D, h, m, s = string.match(d, '(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)')\n        return dateStr(os.time({ day = D, month = M, year = Y, hour = h, min = m, sec = s }))\n    end\n    local now = os.time()\n    local dx = now - d\n    if dx < 600 then\n        return '刚刚'\n    elseif dx < 3600 then\n        return math.floor(dx / 60) .. '分钟前'\n    elseif dx < 3600 * 24 then\n        return math.floor(dx / 3600) .. '小时前'\n    else\n        return os.date('%y-%m-%d', d)\n    end\nend\n\n\nlocal function newInstance(rid)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            ListView,\n            id = \"listview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        RelativeLayout,\n        layout_width = \"fill\",\n        layout_height = \"wrap\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"12dp\",\n        paddingTop = \"16dp\",\n        paddingBottom = \"16dp\",\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_width = \"110dp\",\n            layout_height = \"83dp\",\n            layout_marginRight = \"12dp\",\n            scaleType = \"centerCrop\",\n        },\n        {\n            TextView,\n            id = \"tv_title\",\n            layout_toRightOf = \"iv_image\",\n            layout_width = \"fill\",\n            maxLines = \"2\",\n            lineSpacingMultiplier = 1.3,\n            textSize = \"16sp\",\n            textColor = \"#222222\",\n        },\n        {\n            LinearLayout,\n            id = \"layout_imgs\",\n            layout_below = \"tv_title\",\n            layout_marginTop = \"8dp\",\n            layout_marginBottom = \"8dp\",\n            layout_width = \"match\",\n        },\n        {\n            TextView,\n            id = \"tv_date\",\n            layout_below = \"layout_imgs\",\n            layout_toRightOf = \"iv_image\",\n            layout_alignParentBottom = true,\n            layout_width = \"fill\",\n            textSize = \"12sp\",\n            textColor = \"#aaaaaa\",\n        }\n    }\n    local singleImg = {\n        ImageView,\n        layout_width = (uihelper.getScreenWidth() - uihelper.dp2px(44)) / 3,\n        layout_height = \"83dp\",\n        layout_marginRight = \"8dp\",\n        scaleType = \"centerCrop\",\n    }\n\n    local hadLoadData\n    local isVisible\n    local lastId\n    local params = { rid = rid, page = 0 }\n    local data = {}\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(params, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        convertView.getLayoutParams().width = parent.getWidth()\n                        convertView.setTag(views)\n                    end\n                    local views = convertView.getTag()\n                    local item = data[position]\n                    if item then\n                        if item.imgextra and #item.imgextra > 0 then\n\n                            views.iv_image.setVisibility(8)\n                            views.layout_imgs.setVisibility(0)\n                            views.layout_imgs.removeAllViews()\n                            item.imgextra[#item.imgextra + 1] = { imgsrc = item.imgsrc }\n                            local len = #item.imgextra\n                            if len > 3 then len = 3 end\n                            for i = 1, len do\n                                local img = loadlayout(singleImg, {}, LinearLayout)\n                                LuaImageLoader.load(img, item.imgextra[i].imgsrc)\n                                views.layout_imgs.addView(img)\n                            end\n                        else\n                            views.iv_image.setVisibility(0)\n                            views.layout_imgs.setVisibility(8)\n                            LuaImageLoader.load(views.iv_image, item.imgsrc)\n                        end\n                        views.tv_date.setText(string.format('%s        %s', dateStr(item.ptime), item.source))\n                        views.tv_title.setText(item.title)\n                    end\n\n                    if position == #data then getData(params, data, adapter, fragment, ids.swipe_layout) end\n\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    launchDetail(fragment, data[position + 1])\n                end,\n            }))\n            ids.swipe_layout.setRefreshing(true)\n            ids.swipe_layout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    getData(params, data, adapter, fragment, ids.swipe_layout, true)\n                end\n            }))\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/163news/info.json",
    "content": "{\n  \"id\": \"pub.hanks.163news\",\n  \"name\": \"网易新闻\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b08438866d950f?w=150&h=150&f=png&s=3114\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.9\",\n  \"versionCode\": 10,\n  \"desc\": \"网易新闻客户端\"\n}\n"
  },
  {
    "path": "lua/163news/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\n\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal fragmentNews = require \"163news/fragment_news\"\n\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#FF3333\",\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#FF3333\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\n\ntable.insert(data.fragments, fragmentNews.newInstance('BA8J7DG9wangning'))\ntable.insert(data.titles, '推荐')\n\ntable.insert(data.fragments, fragmentNews.newInstance('BBM54PGAwangning'))\ntable.insert(data.titles, '新闻')\n\ntable.insert(data.fragments, fragmentNews.newInstance('BD29LPUBwangning'))\ntable.insert(data.titles, '国内')\n\ntable.insert(data.fragments, fragmentNews.newInstance('BD29MJTVwangning'))\ntable.insert(data.titles, '国际')\n\ntable.insert(data.fragments, fragmentNews.newInstance('BA8D4A3Rwangning'))\ntable.insert(data.titles, '科技')\n\ntable.insert(data.fragments, fragmentNews.newInstance('BAI6I0O5wangning'))\ntable.insert(data.titles, '手机')\n\ntable.insert(data.fragments, fragmentNews.newInstance('BAI67OGGwangning'))\ntable.insert(data.titles, '军事')\n\ntable.insert(data.fragments, fragmentNews.newInstance('BA8E6OEOwangning'))\ntable.insert(data.titles, '体育')\n\ntable.insert(data.fragments, fragmentNews.newInstance('BCR1UC1Qwangning'))\ntable.insert(data.titles, '社会')\n\ntable.insert(data.fragments, fragmentNews.newInstance('BA10TA81wangning'))\ntable.insert(data.titles, '娱乐')\n\ntable.insert(data.fragments, fragmentNews.newInstance('BA8FF5PRwangning'))\ntable.insert(data.titles, '教育')\n\ntable.insert(data.fragments, fragmentNews.newInstance('BAI6RHDKwangning'))\ntable.insert(data.titles, '图片')\n\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nlocal function unicode_to_utf8(convertStr)\n    local t = {}\n    for a in string.gmatch(convertStr, '\\\\u([0-9a-z][0-9a-z][0-9a-z][0-9a-z])') do\n        if #a == 4 then\n            local n = tonumber(a, 16)\n            assert(n, \"String decoding failed: bad Unicode escape \" .. a)\n            local x\n            if n < 0x80 then\n                x = string.char(n % 0x80)\n            elseif n < 0x800 then\n                -- [110x xxxx] [10xx xxxx]\n                x = string.char(0xC0 + (math.floor(n / 64) % 0x20), 0x80 + (n % 0x40))\n            else\n                -- [1110 xxxx] [10xx xxxx] [10xx xxxx]\n                x = string.char(0xE0 + (math.floor(n / 4096) % 0x10), 0x80 + (math.floor(n / 64) % 0x40), 0x80 + (n % 0x40))\n            end\n            convertStr = string.gsub(convertStr, '\\\\u' .. a, x)\n        end\n    end\n    return convertStr\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    viewPager.setAdapter(adapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\n    tab.setSelectedTabIndicatorColor(0xffffffff)\n    tab.setTabTextColors(0x88ffffff, 0xffffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n"
  },
  {
    "path": "lua/500px/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.os.Build\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal floor = math.floor\nlocal tonum = tonumber\nlocal imageWidth = uihelper.getScreenWidth()\n\nlocal function getData(params, data, adapter, fragment, swipe_layout, reload)\n    local url = string.format('https://api.qingmang.me/v2/article.list?token=c400a7e21688496ca3e7f17c6b0d1846&category_id=%s', params.rid)\n    if params.nextUrl then url = params.nextUrl end\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then return end\n        local json = JSON.decode(body)\n        if json.hasMore and json.nextUrl then params.nextUrl = json.nextUrl end\n        local arr = json.articles\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                for k, _ in ipairs(data) do data[k] = nil end\n            end\n            local s = #data\n            for i = 1, #arr do\n                local item = arr[i]\n                if #item.images > 0 then\n                    data[#data + 1] = {\n                        imgUrl = item.images[1].url,\n                        calcHeight = floor(imageWidth * tonum(item.images[1].height) / tonum(item.images[1].width))\n                    }\n                end\n            end\n            adapter.notifyItemRangeChanged(s, #arr)\n            swipe_layout.setRefreshing(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, data, index)\n    local args = { uris = {}, currentIndex = index }\n    for i = 1, #data do\n        args.uris[i] = data[i].imgUrl\n    end\n    PicturePreviewActivity.start(fragment.getActivity(), JSON.encode(args))\nend\n\nlocal function newInstance(rid)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            RecyclerView,\n            id = \"recyclerView\",\n            background = '#EEEEEE',\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"200dp\",\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n            scaleType = \"fitXY\",\n        },\n        {\n            View,\n            id = \"layer\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n            background = '@drawable/layout_selector_tran',\n        },\n    }\n\n\n    local hadLoadData\n    local isVisible\n    local lastId\n    local params = { rid = rid }\n    local data = {}\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(params, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n                getItemCount = function() return #data end,\n                onCreateViewHolder = function(parent, viewType)\n                    local views = {}\n                    local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n                    holder.itemView.getLayoutParams().width = imageWidth\n                    holder.itemView.setTag(views)\n                    views.layer.onClick = function(view)\n                        local position = holder.getAdapterPosition()\n                        launchDetail(fragment, data, position)\n                    end\n                    return holder\n                end,\n                onBindViewHolder = function(holder, position)\n                    position = position + 1\n                    local item = data[position]\n                    local views = holder.itemView.getTag()\n                    holder.itemView.getLayoutParams().height = item.calcHeight\n                    LuaImageLoader.load(views.iv_image, item.imgUrl)\n                    if position == #data then getData(params, data, adapter, fragment, ids.swipe_layout) end\n                end,\n            }))\n            ids.recyclerView.setLayoutManager(LinearLayoutManager(activity))\n            ids.recyclerView.setAdapter(adapter)\n            ids.swipe_layout.setRefreshing(true)\n            ids.swipe_layout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    getData(params, data, adapter, fragment, ids.swipe_layout, true)\n                end\n            }))\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/500px/info.json",
    "content": "{\n  \"id\": \"pub.hanks.500px\",\n  \"name\": \"500px\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b0842c3273e0c5?w=150&h=150&f=png&s=3578\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.2\",\n  \"versionCode\": 3,\n  \"desc\": \"500px 图片\"\n}\n"
  },
  {
    "path": "lua/500px/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"android.support.design.widget.CoordinatorLayout\"\nimport \"pub.hydrogen.android.R\"\nimport \"android.net.Uri\"\nimport \"android.support.design.widget.AppBarLayout\"\nimport \"android.support.design.widget.CollapsingToolbarLayout\"\nimport \"android.os.Build\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal fragmentNews = require \"500px/fragment_news\"\nlocal AppBarLayoutScrollingViewBehavior = import \"android.support.design.widget.AppBarLayout$ScrollingViewBehavior\"\n-- create view table\nlocal layout = {\n    CoordinatorLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    background = \"#eeeeee\",\n    {\n        AppBarLayout,\n        id = \"appbar\",\n        layout_width = \"match\",\n        {\n            LinearLayout,\n            layout_width = \"fill\",\n            orientation = \"vertical\",\n            applayout_scrollFlags = 0x15,\n            {\n                View,\n                id = \"statusBar\",\n                background = '#FF111111',\n                layout_width = \"fill\",\n            },\n            {\n                Toolbar,\n                background = '#FF111111',\n                id = 'toolbar',\n                layout_width = \"match\",\n                layout_height = \"48dp\",\n                titleTextColor = \"#88ffffff\",\n                {\n                    TabLayout,\n                    id = \"tab\",\n                    layout_width = \"match\",\n                    layout_height = \"match\",\n                },\n            },\n        },\n    },\n    {\n        FrameLayout,\n        applayout_behavior = AppBarLayoutScrollingViewBehavior(),\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\ntable.insert(data.fragments, fragmentNews.newInstance('p280'))\ntable.insert(data.titles, '编辑精选')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3473'))\ntable.insert(data.titles, '热门')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3475'))\ntable.insert(data.titles, '抽象')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3477'))\ntable.insert(data.titles, '动物')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3479'))\ntable.insert(data.titles, '黑白')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3481'))\ntable.insert(data.titles, '名人')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3483'))\ntable.insert(data.titles, '城市与建筑')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3487'))\ntable.insert(data.titles, '音乐会')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3489'))\ntable.insert(data.titles, '家庭')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3493'))\ntable.insert(data.titles, '电影')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3495'))\ntable.insert(data.titles, '艺术')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3497'))\ntable.insert(data.titles, '美食')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3499'))\ntable.insert(data.titles, '新闻')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3501'))\ntable.insert(data.titles, '风景')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3503'))\ntable.insert(data.titles, '微距')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3505'))\ntable.insert(data.titles, '自然')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3507'))\ntable.insert(data.titles, '人物')\n\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3509'))\ntable.insert(data.titles, '表演艺术')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3511'))\ntable.insert(data.titles, '运动')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3513'))\ntable.insert(data.titles, '静物')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3515'))\ntable.insert(data.titles, '街拍')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3517'))\ntable.insert(data.titles, '交通')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3519'))\ntable.insert(data.titles, '旅行')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3521'))\ntable.insert(data.titles, '水下摄影')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3523'))\ntable.insert(data.titles, '城市探索')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3525'))\ntable.insert(data.titles, '婚礼')\n\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    activity.setSupportActionBar(toolbar)\n    activity.setStatusBarColor(0x33000000)\n    activity.setTitle('')\n    toolbar.setNavigationIcon(LuaDrawable.create('500px/500px.png'))\n    local h = 0\n    if Build.VERSION.SDK_INT >= 21 then h = uihelper.dp2px(25) end\n    statusBar.getLayoutParams().height = h\n\n    viewPager.setAdapter(adapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\n    tab.setSelectedTabIndicatorColor(0xeeffffff)\n    tab.setTabTextColors(0x88ffffff, 0xeeffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n\n"
  },
  {
    "path": "lua/91pic/info.json",
    "content": "{\n  \"id\": \"pub.hanks.91pic\",\n  \"name\": \"91 美女\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b084ebc4a73a6f?w=150&h=150&f=png&s=2897\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 2,\n  \"desc\": \"大量高清图\"\n}\n"
  },
  {
    "path": "lua/91pic/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"android.graphics.BitmapFactory\"\nimport \"java.io.File\"\nimport \"java.lang.Thread\"\nlocal BitmapFactory_Options = import \"android.graphics.BitmapFactory$Options\"\n\n\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\nlocal md5 = require \"md5\"\n\nlocal adapter\nlocal imageWidth = uihelper.getScreenWidth()\nlocal data = {}\nlocal list = {\n    page = 1,\n    index = 1,\n    subList = {}\n}\n\n-- create view table\nlocal layout = {\n    RelativeLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        RecyclerView,\n        id = \"recyclerView\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n    {\n        TextView,\n        id = \"tv_loading\",\n        text = \"加载中....\",\n        textSize = \"12sp\",\n        textColor = \"#888888\",\n        layout_margin = \"16dp\",\n        layout_alignParentBottom = true,\n        layout_alignParentRight = true,\n    }\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"225dp\",\n    },\n    {\n        View,\n        id = \"layer\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        background = \"@drawable/layout_selector_tran\",\n        clickable = true,\n    },\n}\n\nlocal function calcImgInfo(filePath, info)\n    if not File(filePath).exists() then\n        info.h = uihelper.dp2px(240)\n        info.w = imageWidth\n        info.localUrl = info.url\n        return\n    end\n    local options = BitmapFactory_Options()\n    options.inJustDecodeBounds = true\n    local bitmap = BitmapFactory.decodeFile(filePath, options)\n    info.h = options.outHeight\n    info.w = options.outWidth\n    info.localUrl = filePath\nend\n\nlocal function notifyUI(arr)\n    uihelper.runOnUiThread(activity, function()\n        local s = #data\n        for i = 1, #arr do\n            local item = arr[i]\n            item.calcHeight = math.floor(imageWidth * item.h / item.w)\n            data[#data + 1] = item\n        end\n        tv_loading.setVisibility(8)\n        adapter.notifyItemRangeChanged(s, #data)\n    end)\nend\n\nlocal function downloadFile(urls, i, arr)\n    local item = {}\n    item.url = urls[i]\n    local filePath = activity.getExternalCacheDir().getAbsolutePath() .. \"/\" .. md5.sumhexa(item.url)\n    if File(filePath).exists() then\n        calcImgInfo(filePath, item)\n        arr[#arr + 1] = item\n        if #arr == #urls then notifyUI(arr) end\n    else\n        LuaHttp.request({ url = item.url, outputFile = filePath }, function(e, code, path)\n            calcImgInfo(path, item)\n            arr[#arr + 1] = item\n            if #arr == #urls then notifyUI(arr) end\n        end)\n    end\nend\n\nlocal function fetchData()\n    tv_loading.setVisibility(0)\n    local url =string.format('http://m.hao123.com/hao123_api/a/tupian/more?pn=%d&tag=meinv', list.page)\n    print(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then\n            print('error', code, url)\n            return\n        end\n\n        local arr = {}\n        local urls = {}\n\n        local json = JSON.decode(body).data\n        for i = 1, #json.data do\n            local item = json.data[i]\n            for j = 1, #item.img_list do\n                local img = item.img_list[j].img.l\n                urls[#urls + 1] = img\n            end\n        end\n\n        for i = 1, #urls do\n            downloadFile(urls, i, arr)\n        end\n\n        list.page = list.page + 1\n    end)\nend\n\nlocal function launchDetail(item)\n    if item == nil or item.url == nil then return end\n    local args = { uris = { item.url } }\n    PicturePreviewActivity.start(activity, JSON.encode(args))\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.getLayoutParams().width = imageWidth\n            holder.itemView.setTag(views)\n            views.layer.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1\n                launchDetail(data[position])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            views.iv_image.getLayoutParams().height = item.calcHeight\n            LuaImageLoader.load(views.iv_image, item.localUrl)\n            if position == #data then fetchData() end\n        end,\n    }))\n    recyclerView.setLayoutManager(LinearLayoutManager(activity))\n    recyclerView.setAdapter(adapter)\n    fetchData()\nend\n"
  },
  {
    "path": "lua/appinn/activity_news_detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nlocal uihelper = require \"uihelper\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#B64926\",\n    {\n        LinearLayout,\n        orientation = \"horizontal\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#B64926\",\n        gravity = \"center_vertical\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginLeft = \"8dp\",\n            scaleType = \"centerInside\",\n            src = \"@drawable/ic_menu_back\",\n        },\n        {\n            TextView,\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            singleLine = true,\n            textIsSelectable = true,\n            ellipsize = \"end\",\n            id = \"tv_title\",\n            gravity = \"center_vertical\",\n            paddingLeft = \"8dp\",\n            textColor = \"#ffffff\",\n            textSize = \"16sp\",\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            LuaWebView,\n            id = \"webview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        },\n        {\n            FrameLayout,\n            layout_gravity = 85,\n            layout_width = \"100dp\",\n            layout_height = \"100dp\",\n            id = \"layout_content\",\n        }\n    }\n}\n\nlocal css = [[\n    video{width:100%}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-webkit-text-size-adjust:100%}body{font-family:'Helvetica Neue',Helvetica,Arial,Sans-serif;background:#fff;padding-top:0;margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0}h1,h2,h3,h4,h5,h6{font-size:16px}abbr[title]{border-bottom:1px dotted}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:\\201C\\201D\\2018\\2019}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0;vertical-align:middle;color:transparent;font-size:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}table{border-collapse:collapse;border-spacing:0;overflow:hidden}a{text-decoration:none}blockquote{border-left:3px solid #d0e5f2;font-style:normal;display:block;vertical-align:baseline;font-size:100%;margin:.5em 0;padding:0 0 0 1em}ul,ol{padding-left:20px}.content{color:#444;line-height:1.6em;font-size:16px;margin:16px}.content img{max-width:100%;display:block;margin:30px auto}.content img+img{margin-top:15px}.content img[src*=\"zhihu.com/equation\"]{display:inline-block;margin:0 3px}.content a{color:#259}.content a:hover{text-decoration:underline}\n]]\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html>\n<head>\n\t<title></title>\n\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n\t<meta name=\"viewport\" content=\"width=device-width; initial-scale=1; minimum-scale=1; maximum-scale=2\">\n\t<meta content=\"width=device-width,user-scalable=no\" name=\"viewport\">\n\t<style type=\"text/css\">\t%s </style>\n</head>\n<body>\n<div class=\"content\"> %s </div>\n<script type=\"text/javascript\">\nfunction openImgActivity(a,b){var c=JSON.stringify({currentIndex:b,uris:a});var d=\"hydrogen://pub.hydrogen.android?action=open_img&data=\"+c;var e=document.createElement(\"iframe\");e.src=d;e.style.display=\"none\";document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},2000)}function init(){var a=document.querySelectorAll(\".content img\");for(var b=0;b<a.length;b++){a[b].addEventListener(\"click\",function(g){var e=g.target||g.srcElement;var c=[];var d=0;var h=document.querySelectorAll(\".content img\");for(var f=0;f<h.length;f++){c[f]=h[f].getAttribute(\"src\");if(e.getAttribute(\"src\").indexOf(c[f])!=-1){d=f}}openImgActivity(c,d)})}}init();\n</script>\n</body>\n</html>\n]]\n\nlocal function html_unescape(s)\n    return s:gsub(\"&lt;\", \"<\"):gsub(\"&gt;\", \">\"):gsub(\"&amp;\", \"&\"):gsub(\"&quot;\", '\"'):gsub(\"&#39;\", \"'\"):gsub(\"&#47;\", \"/\")\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0xffB64926)\n    activity.setContentView(loadlayout(layout))\n    back.onClick = function()\n        activity.finish()\n    end\n    local url = activity.getIntent().getStringExtra('url')\n    tv_title.setText(url or \"error url\")\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local content = string.match(body, 'class=\"entry[-]content\".->(.-)<div%s+class=\\'os[-]share[-]box\\'')\n        local data = string.format(htmlTemplate, css, html_unescape(content))\n        uihelper.runOnUiThread(activity, function()\n            -- print(data)\n            webview.loadData(data, \"text/html; charset=UTF-8\", nil)\n        end)\n    end)\nend\n\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend\n"
  },
  {
    "path": "lua/appinn/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.os.Build\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require(\"log\")\nlocal function getData(params, data, adapter, fragment, swipe_layout, reload)\n    if reload then\n        params.page = 1\n    end\n    local url = \"https://feeds.appinn.com/appinns/\"\n    print(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then return end\n        params.page = params.page + 1\n        local arr = {}\n        for div in string.gmatch(body, '<item>(.-)</item>') do\n            local title, url, content, img = string.match(div,'<title>(.-)</title>%s+<link>(.-)</link>.-<description><!.CDATA.(.-)...</description>.-<img%s+src=\"(.-)\"')\n            local item = {title = title, url = url, content = content, img=img }\n            arr[#arr + 1] = item\n        end\n--        log.print_r(arr)\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                for k, _ in ipairs(data) do data[k] = nil end\n            end\n            local s = #data\n            for i = 1, #arr do\n                data[#data + 1] = arr[i]\n            end\n            adapter.notifyDataSetChanged()\n            swipe_layout.setRefreshing(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, item)\n    local activity = fragment.getActivity()\n    if item == nil or item.url == nil then\n        activity.toast('没有 url 可以打开')\n        return\n    end\n    WebViewActivity.start(activity, item.url, 0xffB64926)\nend\n\nlocal function newInstance()\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            ListView,\n            id = \"listview\",\n            background = '#FFFFFF',\n            dividerHeight = 0,\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"114dp\",\n        paddingLeft = \"8dp\",\n        paddingRight = \"8dp\",\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_marginTop=\"12dp\",\n            layout_gravity = \"right\",\n            layout_width = \"90dp\",\n            layout_height = \"90dp\",\n            scaleType = \"centerCrop\",\n        },\n        {\n            TextView,\n            layout_marginTop=\"12dp\",\n            id = \"tv_title\",\n            layout_width = \"fill\",\n            layout_marginRight = \"100dp\",\n            maxLines = 2,\n            lineSpacingMultiplier = 1.1,\n            textSize = \"14sp\",\n            textColor = \"#333333\",\n        },\n        {\n            TextView,\n            layout_gravity = \"bottom\",\n            id = \"tv_desc\",\n            layout_width = \"fill\",\n            layout_marginRight = '100dp',\n            layout_marginBottom = '12dp',\n            maxLines = 3,\n            lineSpacingMultiplier = 1.1,\n            textSize = \"11sp\",\n            textColor = \"#888888\",\n        },\n        {View, layout_width = \"fill\", layout_height = \"1dp\", background=\"#f1f1f1\",},\n    }\n\n\n    local hadLoadData\n    local isVisible\n    local lastId\n    local params = { rid = rid, page = 1}\n    local data = {}\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(params, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        convertView.getLayoutParams().width = parent.getWidth()\n                        convertView.setTag(views)\n                        views.tv_title.setTypeface(nil, 1);\n                    end\n                    local views = convertView.getTag()\n                    local item = data[position]\n                    if item then\n                        if item.img then\n                            views.iv_image.setVisibility(0)\n                            pcall(function() \n                                print(item.img)\n                                LuaImageLoader.load(views.iv_image, item.img or \"\")\n                            end)\n                        else\n                            views.iv_image.setVisibility(8)\n                        end\n                        views.tv_title.setText(item.title or '')\n                        views.tv_desc.setText(item.content or '')\n                    end\n                    if position == #data then getData(params, data, adapter, fragment, ids.swipe_layout) end\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    launchDetail(fragment, data[position + 1])\n                end,\n            }))\n            ids.swipe_layout.setRefreshing(true)\n            ids.swipe_layout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    getData(params, data, adapter, fragment, ids.swipe_layout, true)\n                end\n            }))\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/appinn/info.json",
    "content": "{\n  \"id\": \"pub.hanks.appinn\",\n  \"name\": \"小众软件\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b0841951ea3770?w=150&h=150&f=png&s=7765\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 2,\n  \"desc\": \"小众软件\"\n}\n"
  },
  {
    "path": "lua/appinn/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\n\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\n\nlocal fragmentNews = require \"appinn/fragment_news\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#B64926\",\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#B64926\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\n\ntable.insert(data.fragments, fragmentNews.newInstance())\ntable.insert(data.titles, '最新')\n\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0xffB64926)\n    activity.setContentView(loadlayout(layout))\n    viewPager.setAdapter(adapter)\n    tab.setSelectedTabIndicatorColor(0xffffffff)\n    tab.setTabTextColors(0x88ffffff, 0xffffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n"
  },
  {
    "path": "lua/bilibili/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\n\nlocal function getData(rid, data, adapter, fragment, swipe_layout)\n    if rid == nil then rid = 0 end\n    local url = string.format('https://api.bilibili.com/x/web-interface/ranking?rid=%d&day=3&jsonp=jsonp', rid)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then return end\n        local arr = JSON.decode(body).data.list\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            for i = 1, #arr do\n                data[#data + 1] = arr[i]\n            end\n            adapter.notifyDataSetChanged()\n            swipe_layout.setRefreshing(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, item)\n    local activity = fragment.getActivity()\n    if item and item.aid then\n        local url = string.format('https://m.bilibili.com/video/av%d.html', item.aid)\n        WebViewActivity.start(activity, url, 0xFFfb7299)\n        return\n    end\n    activity.toast('没有 url 可以打开')\nend\n\nfunction newInstance(rid)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            ListView,\n            id = \"listview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"wrap\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"12dp\",\n        paddingTop = \"12dp\",\n        paddingBottom = \"12dp\",\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_gravity = \"center_vertical\",\n            layout_width = \"120dp\",\n            layout_height = \"75dp\",\n            scaleType = \"centerCrop\",\n        },\n        {\n            TextView,\n            id = \"tv_title\",\n            layout_marginLeft = \"132dp\",\n            layout_width = \"fill\",\n            maxLines = \"2\",\n            lineSpacingMultiplier = 1.3,\n            layout_gravity = \"top\",\n            textSize = \"14sp\",\n            textColor = \"#222222\",\n        },\n        {\n            TextView,\n            id = \"tv_date\",\n            layout_gravity = \"bottom\",\n            layout_marginLeft = \"132dp\",\n            layout_width = \"fill\",\n            textSize = \"12sp\",\n            textColor = \"#aaaaaa\",\n        }\n    }\n    local hadLoadData\n    local isVisible\n    local lastId\n    local data = {}\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(rid, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        convertView.getLayoutParams().width = parent.getWidth()\n                        convertView.setTag(views)\n                    end\n                    local views = convertView.getTag()\n                    local item = data[position]\n                    if item then\n                        LuaImageLoader.load(views.iv_image, item.pic)\n                        views.tv_date.setText(string.format('%d 次播放        %d 条弹幕', item.play, item.video_review))\n                        views.tv_title.setText(item.title)\n                    end\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    launchDetail(fragment, data[position + 1])\n                end,\n            }))\n            ids.swipe_layout.setRefreshing(true)\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/bilibili/info.json",
    "content": "{\n  \"id\": \"pub.hanks.bilibili\",\n  \"name\": \"B站排行\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b08515d3498769?w=150&h=150&f=png&s=2690\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.3\",\n  \"versionCode\": 5,\n  \"desc\": \"B站各大分类排行\"\n}\n"
  },
  {
    "path": "lua/bilibili/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\n\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\n\nlocal fragmentNews = require \"bilibili/fragment_news\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#fb7299\",\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#fb7299\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\n\ntable.insert(data.fragments, fragmentNews.newInstance(0))\ntable.insert(data.titles, '全站')\n\ntable.insert(data.fragments, fragmentNews.newInstance(1))\ntable.insert(data.titles, '动画')\n\ntable.insert(data.fragments, fragmentNews.newInstance(33))\ntable.insert(data.titles, '番剧')\n\ntable.insert(data.fragments, fragmentNews.newInstance(167))\ntable.insert(data.titles, '国创')\n\ntable.insert(data.fragments, fragmentNews.newInstance(23))\ntable.insert(data.titles, '电影')\n\ntable.insert(data.fragments, fragmentNews.newInstance(11))\ntable.insert(data.titles, '电视剧')\n\ntable.insert(data.fragments, fragmentNews.newInstance(3))\ntable.insert(data.titles, '音乐')\n\ntable.insert(data.fragments, fragmentNews.newInstance(129))\ntable.insert(data.titles, '舞蹈')\n\ntable.insert(data.fragments, fragmentNews.newInstance(4))\ntable.insert(data.titles, '游戏')\n\ntable.insert(data.fragments, fragmentNews.newInstance(36))\ntable.insert(data.titles, '科技')\n\ntable.insert(data.fragments, fragmentNews.newInstance(160))\ntable.insert(data.titles, '生活')\n\ntable.insert(data.fragments, fragmentNews.newInstance(119))\ntable.insert(data.titles, '鬼畜')\n\ntable.insert(data.fragments, fragmentNews.newInstance(155))\ntable.insert(data.titles, '时尚')\n\ntable.insert(data.fragments, fragmentNews.newInstance(5))\ntable.insert(data.titles, '娱乐')\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n\n    activity.setContentView(loadlayout(layout))\n    viewPager.setAdapter(adapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\n    tab.setSelectedTabIndicatorColor(0xffffffff)\n    tab.setTabTextColors(0x88ffffff, 0xffffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n"
  },
  {
    "path": "lua/btmayi/info.json",
    "content": "{\n  \"id\": \"pub.hanks.btmayi\",\n  \"name\": \"磁力搜索\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b0851da6780af1?w=150&h=150&f=png&s=337\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.0\",\n  \"versionCode\": 2,\n  \"desc\": \"BT 磁力链搜索\"\n}\n"
  },
  {
    "path": "lua/btmayi/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- douban - hot movie\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.text.SpannableStringBuilder\"\nimport \"java.util.regex.Pattern\"\nimport \"java.util.regex.Matcher\"\nimport \"android.text.style.ForegroundColorSpan\"\nimport \"android.net.Uri\"\n\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\nlocal log = require(\"log\")\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    statusBarColor = \"#DB3C2E\",\n    {\n        LinearLayout,\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#DB3C2E\",\n        {\n            EditText,\n            id = 'et_key',\n            layout_weight = 1,\n            layout_height = \"match\",\n            background = \"#00DB3C2E\",\n            gravity = \"center_vertical\",\n            paddingLeft = '12dp',\n            hint = \"磁力搜索\",\n            textColor = \"#FFFFFF\",\n            hintTextColor = '#88ffffff',\n            singleLine = true,\n            maxLines = 1,\n            textSize = \"14sp\",\n        },\n        {\n            ImageView,\n            id = 'iv_search',\n            layout_width = \"48dp\",\n            layout_height = \"48dp\",\n            padding = '12dp',\n            src = '#btmayi/search.png',\n            background = '@drawable/layout_selector_tran',\n        },\n    },\n    {\n        RelativeLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            RecyclerView,\n            id = \"recyclerView\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        },\n        {\n            TextView,\n            id = \"tv_loading\",\n            text = \"加载中....\",\n            textSize = \"12sp\",\n            textColor = \"#888888\",\n            layout_margin = \"16dp\",\n            visibility = 8,\n            layout_alignParentBottom = true,\n            layout_alignParentRight = true,\n        }\n    }\n}\n\nlocal item_view = {\n    LinearLayout,\n    orientation = 'vertical',\n    layout_width = \"match\",\n    background = '@drawable/layout_selector_tran',\n    paddingTop = \"16dp\",\n    {\n        TextView,\n        lineSpacingMultiplier = 1.3,\n        id = \"tv_title\",\n        layout_width = \"fill\",\n        paddingLeft = '12dp',\n        paddingRight = '12dp',\n        textSize = \"14sp\",\n        textColor = \"#222222\",\n    },\n    {\n        TextView,\n        layout_width = \"fill\",\n        layout_marginTop = '8dp',\n        paddingLeft = '12dp',\n        paddingRight = '12dp',\n        id = \"tv_desc\",\n        textSize = \"11sp\",\n        textColor = \"#888888\",\n    },\n    {\n        TextView,\n        layout_width = \"fill\",\n        layout_height = \"30dp\",\n        paddingLeft = '12dp',\n        paddingRight = '12dp',\n        gravity = 'center_vertical',\n        id = \"tv_magnet\",\n        visibility = 8,\n        background = '@drawable/layout_selector_tran',\n        textSize = \"10sp\",\n        textColor = \"#234567\",\n    },\n    {\n        ProgressBar,\n        id = 'pb_loading',\n        layout_width = \"16dp\",\n        layout_height = \"16dp\",\n        layout_margin = '12dp',\n        visibility = 8,\n    },\n    {\n        View,\n        layout_width = \"match\",\n        layout_height = 2,\n        layout_marginTop = '16dp',\n        background = '#e1e1e1',\n    }\n}\n\n\nlocal data = {}\nlocal params = { key = '', page = 1 }\nlocal adapter\n\nlocal function copyText(text)\n    local clipboard = activity.getSystemService(Context.CLIPBOARD_SERVICE)\n    local clip = ClipData.newPlainText(\"氢应用\", text)\n    clipboard.setPrimaryClip(clip)\n    activity.toast('已复制到剪切板')\nend\n\nlocal function openOrCopy(item)\n    if item.magnet == nil then\n        activity.toast('磁力链不可用')\n        return\n    end\n    copyText(item.magnet)\n    activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(item.magnet)))\nend\n\nlocal function getData()\n    if params.key == nil or params.key == '' then return end\n    tv_loading.setVisibility(0)\n    local url = string.format('http://www.cilicili8.com/search/%s/?c=&s=create_time&p=%d', params.key, params.page)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then\n            print('fetch data error')\n            return\n        end\n        uihelper.runOnUiThread(activity, function()\n            tv_loading.setVisibility(8)\n            if params.page == 1 then\n                for i, v in ipairs(data) do\n                    data[i] = nil\n                end\n            end\n            params.page = params.page + 1\n            for title, url, info in string.gmatch(body, '<div class=\"x[-]item row\">.-<a title=\"(.-)\".-href=\"(.-)\".-class=\"tail\">(.-)</div>') do\n                info = info:gsub(\"^%s+\", \"\"):gsub(\"%s+$\", \"\")\n                url = 'http://www.cilicili8.com' .. url\n                data[#data + 1] = { title = title, info = info, url = url }\n            end\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nlocal function launchDetail(position)\n    local item = data[position + 1]\n    item.loading = true\n    adapter.notifyItemChanged(position)\n    LuaHttp.request({ url = item.url }, function(e, c, body)\n        local magnet = string.match(body, \"magnetQRCode[(]'(.-)'\")\n        item.magnet = magnet\n        item.loading = false,\n        uihelper.runOnUiThread(activity, function() adapter.notifyItemChanged(position) end)\n    end)\nend\n\nfunction onDestroy()\n    LuaHttp.cancelAll()\nend\n\nlocal function highlight(text, key)\n    local spannable = SpannableStringBuilder(text)\n    local p = Pattern.compile(key)\n    local m = p.matcher(text)\n    while m.find() do\n        local span = ForegroundColorSpan(0xFFDB3C2E)\n        spannable.setSpan(span, m.start(), m['end'](), 0x21)\n    end\n    return spannable\nend\n\n\nfunction onCreate(savedInstanceState)\n    activity.setLightStatusBar()\n    activity.setContentView(loadlayout(layout))\n    local screenWidth = uihelper.getScreenWidth()\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.setTag(views)\n            holder.itemView.getLayoutParams().width = screenWidth\n            holder.itemView.onClick = function()\n                local p = holder.getAdapterPosition()\n                launchDetail(p)\n            end\n            views.tv_magnet.onClick = function(v)\n                local p = holder.getAdapterPosition() + 1\n                openOrCopy(data[p])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local views = holder.itemView.getTag()\n            if views == nil then return end\n            local item = data[position]\n            if item then\n                views.tv_title.setText(highlight(item.title, params.key))\n                views.tv_desc.setText(item.info)\n                if item.magnet then\n                    views.tv_magnet.setVisibility(0)\n                    views.tv_magnet.setText(item.magnet)\n                else\n                    views.tv_magnet.setVisibility(8)\n                end\n                if item.loading then\n                    views.pb_loading.setVisibility(0)\n                else\n                    views.pb_loading.setVisibility(8)\n                end\n            end\n            if position == #data then getData() end\n        end,\n    }))\n    recyclerView.setLayoutManager(LinearLayoutManager(activity))\n    recyclerView.setAdapter(adapter)\n    iv_search.onClick = function(v)\n        local key = et_key.getText().toString()\n        params.key = key\n        params.page = 1\n        getData()\n    end\n    et_key.setImeOptions(0x00000003)\n    et_key.setOnEditorActionListener(luajava.createProxy('android.widget.TextView$OnEditorActionListener', {\n        onEditorAction = function(v, actionId, event)\n            local key = et_key.getText().toString()\n            params.key = key\n            params.page = 1\n            getData()\n            return false\n        end\n    }))\nend\n"
  },
  {
    "path": "lua/buka/detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- 布卡漫画\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\n\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.support.v7.widget.GridLayoutManager\"\nimport \"android.view.View\"\nimport \"android.support.v4.widget.Space\"\nimport \"androlua.widget.ninegride.LuaNineGridView\"\nimport \"androlua.widget.ninegride.LuaNineGridViewAdapter\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"androlua.widget.webview.WebViewActivity\"\n\n\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\nlocal log = require(\"log\")\nlocal screenWidth = uihelper.getScreenWidth()\n\nimport \"android.support.design.widget.CoordinatorLayout\"\nimport \"android.support.design.widget.AppBarLayout\"\nimport \"android.support.design.widget.CollapsingToolbarLayout\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"android.support.design.widget.FloatingActionButton\"\n\nlocal AppBarLayoutScrollingViewBehavior = import \"android.support.design.widget.AppBarLayout$ScrollingViewBehavior\"\n\n-- create view table\nlocal layout = {\n    CoordinatorLayout,\n    layout_width = \"match\",\n    layout_height = \"match\",\n    {\n        AppBarLayout,\n        id = \"appbar\",\n        layout_width = \"match\",\n        {\n            CollapsingToolbarLayout,\n            id = \"collapsing_toolbar\",\n            applayout_scrollFlags = 0x3,\n            background = \"#ffffff\",\n            layout_width = \"match\",\n            {\n                ImageView,\n                layout_width = \"match\",\n                layout_height = \"240dp\",\n                applayout_collapseMode = 2,\n                id = \"iv_cover\",\n                scaleType = \"centerCrop\",\n            },\n            {\n                View,\n                layout_width = \"match\",\n                layout_height = \"240dp\",\n                applayout_collapseMode = 2,\n                background = \"#22000000\",\n            },\n            {\n                LinearLayout,\n                layout_width = \"match\",\n                applayout_collapseMode = 1,\n                layout_marginTop = \"180dp\",\n                background = \"#ffffff\",\n                orientation = \"vertical\",\n                {\n                    FrameLayout,\n                    padding = \"16dp\",\n                    layout_width = \"match\",\n                    background = \"#2D2118\",\n                    {\n                        TextView,\n                        id = \"tv_title\",\n                        textSize = \"22sp\",\n                        textColor = \"#FFFFFF\",\n                    },\n                    {\n                        TextView,\n                        id = \"tv_updateinfo\",\n                        layout_marginTop = \"34dp\",\n                        textSize = \"14sp\",\n                        textColor = \"#FFFFFF\",\n                    },\n                    {\n                        TextView,\n                        id = \"tv_score\",\n                        layout_gravity = \"right\",\n                        layout_marginTop = \"8dp\",\n                        textSize = \"16sp\",\n                        textColor = \"#FFFFFF\",\n                    },\n                    {\n                        TextView,\n                        id = \"tv_type\",\n                        textSize = \"12sp\",\n                        layout_marginTop = \"60dp\",\n                        textColor = \"#EEFFFFFF\",\n                    },\n                },\n                {\n                    TextView,\n                    id = \"tv_desc\",\n                    padding = \"16dp\",\n                    textSize = \"14sp\",\n                    lineSpacingMultiplier = 1.3,\n                    textColor = \"#444444\",\n                    background = \"#ffffff\",\n                },\n            }\n        },\n    },\n    {\n        RecyclerView,\n        id = \"recyclerView\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        background = \"#ffffff\",\n        applayout_behavior = AppBarLayoutScrollingViewBehavior(),\n    },\n}\n\nlocal item_capter = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_height = \"60dp\",\n    gravity = \"center\",\n    {\n        TextView,\n        layout_height = \"match\",\n        layout_width = \"match\",\n        layout_margin = \"8dp\",\n        gravity = \"center\",\n        id = \"tv_chapter\",\n        textSize = \"13sp\",\n        textColor = \"#444444\",\n        background = \"#C5C8C0\",\n    },\n}\n\nlocal baseInfo = {}\nlocal data = {}\nlocal adapter\n\nlocal function trim(s)\n    if s == nil then return \"\" end\n    return s:gsub(\"^%s+\", \"\"):gsub(\"%s+$\", \"\")\nend\n\nlocal function updateHeader()\n    -- header\n    LuaImageLoader.load(iv_cover, baseInfo.coverImg or '')\n    tv_title.setText(baseInfo.title or '')\n    tv_type.setText(string.format('%s        %s', trim(baseInfo.author), trim(baseInfo.type)))\n    tv_score.setText(baseInfo.score)\n    tv_desc.setText(baseInfo.desc or '')\n    tv_updateinfo.setText(baseInfo.updateInfo or '')\nend\n\nlocal function getData(mid)\n    local url = string.format('http://www.buka.cn/detail/%s', mid)\n    print(url)\n    LuaHttp.request({ url = url, headers={\n        \"User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36\"\n    } }, function(error, code, body)\n        if error or code ~= 200 then\n            print('fetch dm5 data error')\n            return\n        end\n        uihelper.runOnUiThread(activity, function()\n            local coverImg, title = string.match(body, 'class=\"manga.img.-<img src=\"(.-)\".-alt=\"(.-)\"')\n            local updateInfo = string.match(body, '<div class=\"author[-]names\".-<span.->(.-)</span>')\n            local author = string.match(body, '<a .-class=\"author\">(.-)</a>')\n            local desc = string.match(body, '<div class=\"manga[-]desc[-]font\">(.-)</div>')\n            print(coverImg)\n            baseInfo.coverImg = coverImg\n            baseInfo.title = trim(title)\n            baseInfo.type = ''\n            baseInfo.author = author:gsub('%s+', ' ')\n            baseInfo.score = ''\n            baseInfo.updateInfo = updateInfo:gsub('%s+', ' ')\n            baseInfo.desc = trim(desc)\n            updateHeader()\n            for url, name in string.gmatch(body, 'class=\"epsbox.eplink%s+\".-href=\"(.-)\".->(.-)</a>') do\n                data[#data + 1] = { url = url, name = trim(name) }\n            end\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nfunction launchDetail(item)\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", \"buka/viewer.lua\")\n    intent.putExtra(\"url\", item.url)\n    activity.startActivity(intent)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x00000000)\n    activity.setContentView(loadlayout(layout))\n\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            viewType = viewType + 1\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_capter, views, RecyclerView))\n            holder.itemView.setTag(views)\n            holder.itemView.getLayoutParams().width = screenWidth / 4\n            holder.itemView.onClick = function(view)\n                local p = holder.getAdapterPosition() + 1\n                launchDetail(data[p])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local views = holder.itemView.getTag()\n            if views == nil then return end\n            local item = data[position]\n            views.tv_chapter.setText(item.name or '')\n        end,\n    }))\n\n    recyclerView.setLayoutManager(GridLayoutManager(activity, 4))\n    recyclerView.setAdapter(adapter)\n\n    local mid = activity.getIntent().getStringExtra('mid')\n    getData(mid)\nend\n"
  },
  {
    "path": "lua/buka/fragment_category.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"android.view.View\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.GridLayoutManager\"\nimport \"android.view.View\"\nimport \"android.support.v4.widget.Space\"\nimport \"androlua.widget.ninegride.LuaNineGridView\"\nimport \"androlua.widget.ninegride.LuaNineGridViewAdapter\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"androlua.widget.webview.WebViewActivity\"\n\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require(\"log\")\nlocal screenWidth = uihelper.getScreenWidth()\n\nlocal function getData(rid, data, adapter, fragment, swipe_layout)\n    if rid == nil then rid = '/news/getnews' end\n    local url = string.format('http://www.buka.cn%s', rid)\n    local options = {\n        url = url,\n        method = 'POST',\n        headers = { 'X-Requested-With:XMLHttpRequest' },\n        formData = {\n            'start=' .. data.page\n        }\n    }\n    LuaHttp.request(options, function(error, code, body)\n        if error or code ~= 200 then\n            print('fetch buka data error')\n            return\n        end\n        local arr = JSON.decode(body).items\n        uihelper.runOnUiThread(activity, function()\n            for i = 1, #arr do\n                data.items[#data.items + 1] = arr[i]\n            end\n            data.page = data.page + 1\n            adapter.notifyDataSetChanged()\n            swipe_layout.setRefreshing(false)\n            swipe_layout.setEnabled(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, item)\n    local activity = fragment.getActivity()\n    if item and item.mid then\n        local intent = Intent(activity, LuaActivity)\n        intent.putExtra(\"luaPath\", 'buka/detail.lua')\n        intent.putExtra(\"mid\", item.mid)\n        activity.startActivity(intent)\n    end\nend\n\nfunction newInstance(rid)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            RecyclerView,\n            id = \"recyclerView\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n            paddingTop = \"8dp\",\n            paddingLeft = \"4dp\",\n            paddingRight = \"4dp\",\n            clipToPadding = false,\n        },\n    }\n\n    local item_category = {\n        LinearLayout,\n        layout_width = (screenWidth - uihelper.dp2px(8)) / 3,\n        layout_height = \"210dp\",\n        paddingLeft = \"4dp\",\n        paddingRight = \"4dp\",\n        paddingTop = \"8dp\",\n        orientation = \"vertical\",\n        gravity = \"center\",\n        {\n            ImageView,\n            id = \"iv_cover\",\n            layout_width = \"fill\",\n            layout_height = \"160dp\",\n            scaleType = \"centerCrop\",\n        },\n        {\n            TextView,\n            id = \"tv_title\",\n            layout_height = \"26dp\",\n            layout_width = \"match\",\n            padding = \"4dp\",\n            textSize = \"14sp\",\n            textColor = \"#444444\",\n            singleLine = true,\n            ellipsize = \"end\",\n            gravity = \"center\",\n        },\n        {\n            TextView,\n            id = \"tv_info\",\n            layout_height = \"15dp\",\n            layout_width = \"match\",\n            textSize = \"12sp\",\n            textColor = \"#888888\",\n            singleLine = true,\n            ellipsize = \"end\",\n            gravity = \"center\",\n        },\n    }\n\n    local data = { page = 0, items = {} }\n    local hadLoadData\n    local isVisible\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(rid, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n                getItemCount = function()\n                    return #data.items\n                end,\n                getItemViewType = function(position)\n                    return 0\n                end,\n                onCreateViewHolder = function(parent, viewType)\n                    local views = {}\n                    local holder = LuaRecyclerHolder(loadlayout(item_category, views, RecyclerView))\n                    holder.itemView.setTag(views)\n                    holder.itemView.getLayoutParams().width = screenWidth / 3\n                    holder.itemView.onClick = function(v)\n                        local position = holder.getAdapterPosition() + 1\n                        launchDetail(fragment, data.items[position])\n                    end\n                    return holder\n                end,\n                onBindViewHolder = function(holder, position)\n                    position = position + 1\n                    local views = holder.itemView.getTag()\n                    local item = data.items[position]\n                    LuaImageLoader.load(views.iv_cover, item.logo)\n                    views.tv_title.setText(item.name)\n                    views.tv_info.setText(item.lastup)\n                    if position == #data.items then getData(rid, data, adapter, fragment, ids.swipe_layout) end\n                end,\n            }))\n            ids.recyclerView.setLayoutManager(GridLayoutManager(activity, 3))\n            ids.recyclerView.setAdapter(adapter)\n            ids.swipe_layout.setRefreshing(true)\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n \n "
  },
  {
    "path": "lua/buka/info.json",
    "content": "{\n  \"id\": \"pub.hanks.buka\",\n  \"name\": \"布卡漫画\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b0852649adc474?w=150&h=150&f=png&s=3557\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 3,\n  \"desc\": \"布卡漫画\"\n}\n"
  },
  {
    "path": "lua/buka/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\n\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\n\nlocal fragmentNews = require \"buka/fragment_category\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#F4B440\",\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#F4B440\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\ntable.insert(data.fragments, fragmentNews.newInstance('/news/getnews'))\ntable.insert(data.titles, '最近更新')\n\ntable.insert(data.fragments, fragmentNews.newInstance('/ranking/getranking'))\ntable.insert(data.titles, '今日热榜')\n\ntable.insert(data.fragments, fragmentNews.newInstance('/category/12022/已完结'))\ntable.insert(data.titles, '已完结')\n\ntable.insert(data.fragments, fragmentNews.newInstance('/category/12084/最近上新'))\ntable.insert(data.titles, '最近上新')\n\ntable.insert(data.fragments, fragmentNews.newInstance('/category/12053/日韩'))\ntable.insert(data.titles, '日韩')\n\ntable.insert(data.fragments, fragmentNews.newInstance('/category/12036/条漫'))\ntable.insert(data.titles, '条漫')\n\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n\n    activity.setContentView(loadlayout(layout))\n    viewPager.setAdapter(adapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\n    tab.setSelectedTabIndicatorColor(0xffffffff)\n    tab.setTabTextColors(0x88ffffff, 0xffffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n"
  },
  {
    "path": "lua/buka/search.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- 漫本联盟 dm5.com\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\n\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.view.View\"\nimport \"android.support.v4.widget.Space\"\nimport \"androlua.widget.ninegride.LuaNineGridView\"\nimport \"androlua.widget.ninegride.LuaNineGridViewAdapter\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"androlua.widget.webview.WebViewActivity\"\n\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\nlocal log = require(\"log\")\nlocal screenWidth = uihelper.getScreenWidth()\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    statusBarColor = \"#FDE04C\",\n    {\n        RelativeLayout,\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#FDE04C\",\n        {\n            EditText,\n            id = \"et_keyword\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n            layout_marginLeft = \"16dp\",\n            layout_marginRight = \"64dp\",\n            maxLines = 1,\n            background = \"#00FDE04C\",\n            layout_centerInParent = true,\n            hint = \"请输入关键字\",\n            textColor = \"#43250C\",\n            textSize = \"16sp\",\n        },\n        {\n            ImageView,\n            id = \"iv_search\",\n            layout_width = \"56dp\",\n            layout_height = \"56dp\",\n            padding = \"16dp\",\n            layout_alignParentRight = true,\n            src = \"#dm5/ic_search.png\"\n        }\n    },\n    {\n        RecyclerView,\n        id = \"recyclerView\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n}\n\n\nlocal item_topList = {\n    FrameLayout,\n    id = \"layout_top\",\n    layout_height = \"96dp\",\n    padding = \"8dp\",\n    {\n        ImageView,\n        id = \"iv_cover\",\n        layout_width = \"120dp\",\n        layout_height = \"80dp\",\n        scaleType = \"centerCrop\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_marginLeft = \"128dp\",\n        textColor = \"#444444\",\n        textSize = \"14sp\",\n    },\n    {\n        TextView,\n        id = \"tv_subtitle\",\n        layout_marginLeft = \"128dp\",\n        maxLines = 1,\n        textSize = \"12sp\",\n        textColor = \"#767676\",\n        layout_gravity = \"center_vertical\",\n    },\n    {\n        TextView,\n        id = \"tv_info\",\n        layout_marginLeft = \"128dp\",\n        textSize = \"12sp\",\n        textColor = \"#ec4646\",\n        layout_gravity = \"bottom\",\n    },\n    {\n        TextView,\n        id = \"tv_score\",\n        layout_gravity = \"right\",\n        textSize = \"10sp\",\n    },\n}\n\n\nlocal page = 1\nlocal data = {}\nlocal adapter\nlocal lastKey = ''\n\nlocal function search()\n    -- search\n    local key = et_keyword.getText().toString()\n    local reset = false\n    if key ~= lastKey then\n        reset = true\n        lastKey = key\n        page = 1\n    end\n    local options = {\n        url = 'http://m.dm5.com/pagerdata.ashx',\n        method = \"POST\",\n        formData = {\n            \"t:7\",\n            \"f:0\",\n            \"pageindex:\" .. page,\n            \"title:\" .. key,\n        }\n    }\n    log.print_r(options)\n    LuaHttp.request(options, function(e, code, body)\n        if e or code ~= 200 then return end\n        local json = JSON.decode(body)\n        page = page + 1\n        uihelper.runOnUiThread(activity, function()\n            if reset then\n                for k, _ in pairs(data) do data[k] = nil end\n            end\n            for i = 1, #json do\n                data[#data + 1] = json[i]\n            end\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nfunction onDestroy()\n    LuaHttp.cancelAll()\nend\n\nlocal function launchDetail(url)\n    if url:find('^http://') == nil then\n        url = 'http://m.dm5.com' .. url\n    end\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'dm5/detail.lua')\n    intent.putExtra(\"url\", url)\n    activity.startActivity(intent)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    iv_search.onClick = search\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_topList, views, RecyclerView))\n            holder.itemView.setTag(views)\n            holder.itemView.getLayoutParams().width = screenWidth\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            if item == nil or views == nil then return end\n            log.print_r(item)\n            LuaImageLoader.load(views.iv_cover, item.Pic)\n            views.tv_title.setText(item.Title or 'xxxx')\n            views.tv_subtitle.setText(item.Categorys or '--')\n            views.tv_info.setText(item.LastUpdateInfo or '--')\n            views.tv_score.setText(item.Status or '--')\n            views.layout_top.onClick = function()\n                launchDetail(item.Url)\n            end\n\n            if position == #data then\n                search(true)\n            end\n        end,\n    }))\n    recyclerView.setLayoutManager(LinearLayoutManager(activity))\n    recyclerView.setAdapter(adapter)\nend\n"
  },
  {
    "path": "lua/buka/viewer.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaWebView\"\n\nlocal uihelper = require(\"uihelper\")\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        ListView,\n        id = \"listview\",\n        dividerHeight = \"4dp\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n    {\n        LuaWebView,\n        id = \"webview\",\n        layout_height = 1,\n        layout_width = 1,\n        background = '#e1e1e1',\n    }\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    layout_height = \"560dp\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n}\n\nlocal data = {}\nlocal adapter\n\nlocal function getData(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        uihelper.runOnUiThread(activity, function()\n            for url in string.gmatch(body, ' data[-]original=\"(.-)\"') do\n                data[#data + 1] = url\n            end\n            local u = data[1] or 'http://c-r6.sosobook.cn/pics/103915/65603/t4029739_0001.jpg'\n            table.insert(data, 1, u:sub(1, #u - 5) .. '1.jpg')\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nfunction launchDetail(item)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x00000000)\n    activity.setContentView(loadlayout(layout))\n\n    local url = activity.getIntent().getStringExtra('url')\n    if not url:find('^http://') then\n        url = 'http://www.buka.cn' .. url\n    end\n    adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n        getCount = function() return #data end,\n        getView = function(position, convertView, parent)\n            position = position + 1 -- lua 索引从 1开始\n            if convertView == nil then\n                local views = {} -- store views\n                convertView = loadlayout(item_view, views, ListView)\n                convertView.getLayoutParams().width = parent.getWidth()\n                convertView.setTag(views)\n            end\n            local views = convertView.getTag()\n            local item = data[position]\n            print(position, item)\n            if item then\n                LuaImageLoader.load(views.iv_image, item, url)\n            end\n            return convertView\n        end\n    }))\n    listview.setAdapter(adapter)\n    listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n        onItemClick = function(adapter, view, position, id)\n        end,\n    }))\n    getData(url)\nend\n"
  },
  {
    "path": "lua/digit/activity_news_detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nlocal uihelper = require \"uihelper\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#434343\",\n    {\n        LinearLayout,\n        orientation = \"horizontal\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#434343\",\n        gravity = \"center_vertical\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginLeft = \"8dp\",\n            scaleType = \"centerInside\",\n            src = \"@drawable/ic_menu_back\",\n        },\n        {\n            TextView,\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            singleLine = true,\n            textIsSelectable = true,\n            ellipsize = \"end\",\n            id = \"tv_title\",\n            gravity = \"center_vertical\",\n            paddingLeft = \"8dp\",\n            textColor = \"#ffffff\",\n            textSize = \"16sp\",\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            LuaWebView,\n            id = \"webview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal css = [[\n    article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-webkit-text-size-adjust:100%}body{font-family:'Helvetica Neue',Helvetica,Arial,Sans-serif;background:#fff;padding-top:0;margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0}h1,h2,h3,h4,h5,h6{font-size:16px}abbr[title]{border-bottom:1px dotted}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:\\201C\\201D\\2018\\2019}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0;vertical-align:middle;color:transparent;font-size:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}table{border-collapse:collapse;border-spacing:0;overflow:hidden}a{text-decoration:none}blockquote{border-left:3px solid #d0e5f2;font-style:normal;display:block;vertical-align:baseline;font-size:100%;margin:.5em 0;padding:0 0 0 1em}ul,ol{padding-left:20px}.content{color:#444;line-height:1.6em;font-size:16px;margin:16px}.content img{max-width:100%;display:block;margin:30px auto}.content img+img{margin-top:15px}.content img[src*=\"zhihu.com/equation\"]{display:inline-block;margin:0 3px}.content a{color:#259}.content a:hover{text-decoration:underline}\n]]\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html>\n<head>\n    <title></title>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width; initial-scale=1; minimum-scale=1; maximum-scale=2\">\n    <meta content=\"width=device-width,user-scalable=no\" name=\"viewport\">\n    <style type=\"text/css\"> %s </style>\n</head>\n<body>\n<div class=\"content\"> %s </div>\n<script type=\"text/javascript\">\nfunction openImgActivity(a,b){var c=JSON.stringify({currentIndex:b,uris:a});var d=\"hydrogen://pub.hydrogen.android?action=open_img&data=\"+c;var e=document.createElement(\"iframe\");e.src=d;e.style.display=\"none\";document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},2000)}function init(){var a=document.querySelectorAll(\".content img\");for(var b=0;b<a.length;b++){a[b].addEventListener(\"click\",function(g){var e=g.target||g.srcElement;var c=[];var d=0;var h=document.querySelectorAll(\".content img\");for(var f=0;f<h.length;f++){c[f]=h[f].getAttribute(\"src\");if(e.getAttribute(\"src\").indexOf(c[f])!=-1){d=f}}openImgActivity(c,d)})}}init();\n</script>\n</body>\n</html>\n]]\n\n\n\nlocal function getData(url)\n    print(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        \n        local content = string.match(body, '(<div%s+class=\"view_content%s+.-\">.-)<div%s+class=\"viewthread[-]like[-]box\"'):gsub('style=\".-\"', ''):gsub('width=%d+', ''):gsub('height=%d+', '')\n        local data = string.format(htmlTemplate, css, content)\n        uihelper.runOnUiThread(activity, function()\n            webview.loadData(data, \"text/html; charset=UTF-8\", nil)\n        end)\n    end)\nend\n\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    back.onClick = function()\n        activity.finish()\n    end\n    local url = activity.getIntent().getStringExtra('url')\n    tv_title.setText(url)\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    getData(url)\nend\n\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend\n"
  },
  {
    "path": "lua/digit/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.os.Build\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require(\"log\")\nlocal function getData(params, data, adapter, fragment, swipe_layout, reload)\n    local url = string.format('https://api.qingmang.me/v2/article.list?token=c400a7e21688496ca3e7f17c6b0d1846&category_id=%s', params.rid)\n    if params.nextUrl then url = params.nextUrl end\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then return end\n        local json = JSON.decode(body)\n        if json.hasMore and json.nextUrl then params.nextUrl = json.nextUrl end\n        local arr = json.articles\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                for k, _ in ipairs(data) do data[k] = nil end\n            end\n            local s = #data\n            for i = 1, #arr do\n                data[#data + 1] = arr[i]\n            end\n            adapter.notifyDataSetChanged()\n            swipe_layout.setRefreshing(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, item)\n    log.print_r(item)\n    local activity = fragment.getActivity()\n    if item == nil or item.webUrl == nil then\n        activity.toast('没有 url 可以打开')\n        return\n    end\n    local activity = fragment.getActivity()\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'digit/activity_news_detail.lua')\n    intent.putExtra(\"url\", item.webUrl)\n    activity.startActivity(intent)\nend\n\nlocal function newInstance(rid)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            ListView,\n            id = \"listview\",\n            background = '#EEEEEE',\n            dividerHeight = 0,\n            paddingTop = \"8dp\",\n            clipToPadding = false,\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        FrameLayout,\n        layout_width = \"fill\",\n        {\n            LinearLayout,\n            background = '#FFFFFF',\n            layout_marginLeft = \"16dp\",\n            layout_marginRight = \"16dp\",\n            layout_marginTop = \"8dp\",\n            layout_marginBottom = \"8dp\",\n            elevation = \"2dp\",\n            orientation = 'vertical',\n            layout_width = \"fill\",\n            {\n                ImageView,\n                id = \"iv_image\",\n                layout_width = \"fill\",\n                layout_height = \"140dp\",\n                scaleType = \"centerCrop\",\n            },\n            {\n                TextView,\n                id = \"tv_title\",\n                layout_width = \"fill\",\n                layout_margin = '16dp',\n                maxLines = 2,\n                lineSpacingMultiplier = 1.3,\n                textSize = \"16sp\",\n                textColor = \"#434343\",\n            },\n            {\n                TextView,\n                id = \"tv_desc\",\n                layout_width = \"fill\",\n                layout_marginLeft = '16dp',\n                layout_marginRight = '16dp',\n                layout_marginBottom = '16dp',\n                maxLines = 4,\n                lineSpacingMultiplier = 1.3,\n                textSize = \"12sp\",\n                textColor = \"#666666\",\n            },\n        },\n    }\n\n\n    local hadLoadData\n    local isVisible\n    local lastId\n    local params = { rid = rid }\n    local data = {}\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(params, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        convertView.getLayoutParams().width = parent.getWidth()\n                        convertView.setTag(views)\n                        views.tv_title.setTypeface(nil, 1);\n                    end\n                    local views = convertView.getTag()\n                    local item = data[position]\n                    if item then\n                        if item.covers and #item.covers > 0 then\n                            views.iv_image.setVisibility(0)\n                            LuaImageLoader.load(views.iv_image, item.covers[1].url .. '?imageMogr2/quality/95/thumbnail/!1440x480r/gravity/Center/crop/1440x480')\n                        else\n                            views.iv_image.setVisibility(8)\n                        end\n                        views.tv_title.setText(item.title or 'ERROR TITLE')\n                        views.tv_desc.setText(item.snippet or '')\n                    end\n                    if position == #data then getData(params, data, adapter, fragment, ids.swipe_layout) end\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    launchDetail(fragment, data[position + 1])\n                end,\n            }))\n            ids.swipe_layout.setRefreshing(true)\n            ids.swipe_layout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    getData(params, data, adapter, fragment, ids.swipe_layout, true)\n                end\n            }))\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/digit/info.json",
    "content": "{\n  \"id\": \"pub.hanks.digit\",\n  \"name\": \"数字尾巴\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b0852c2ccda17c?w=150&h=150&f=png&s=3953\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 3,\n  \"desc\": \"数字尾巴\"\n}\n"
  },
  {
    "path": "lua/digit/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"pub.hydrogen.android.R\"\nimport \"android.net.Uri\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal fragmentNews = require \"digit/fragment_news\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#FFFFFF\",\n    {\n        Toolbar,\n        background = '#FFFFFF',\n        id = 'toolbar',\n        layout_width = \"match\",\n        layout_height = \"56dp\",\n        titleTextColor = \"#434343\",\n    },\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#FFFFFF\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\ntable.insert(data.fragments, fragmentNews.newInstance('p90'))\ntable.insert(data.titles, '首页')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3333'))\ntable.insert(data.titles, '资讯')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3335'))\ntable.insert(data.titles, '手机')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3339'))\ntable.insert(data.titles, '周边')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3341'))\ntable.insert(data.titles, '影音')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3343'))\ntable.insert(data.titles, '电脑')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3345'))\ntable.insert(data.titles, '数码')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3347'))\ntable.insert(data.titles, '摄影')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3349'))\ntable.insert(data.titles, '旅行')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3351'))\ntable.insert(data.titles, '生活')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3355'))\ntable.insert(data.titles, '玩物')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3357'))\ntable.insert(data.titles, '应用')\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    activity.setSupportActionBar(toolbar)\n    activity.setStatusBarColor(0x33000000)\n    activity.setTitle('数字尾巴')\n    toolbar.setNavigationIcon(LuaDrawable.create('digit/logo.png'))\n    viewPager.setAdapter(adapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\n    tab.setSelectedTabIndicatorColor(0xff434343)\n    tab.setTabTextColors(0x88434343, 0xff434343)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n\nfunction onCreateOptionsMenu(menu)\n    menu.add(\"网页版\")\n    return true\nend\n\nfunction onOptionsItemSelected(item)\n    local title = item.getTitle()\n    if title == \"网页版\" then\n        activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse('http://www.dgtle.com/')))\n    end\nend"
  },
  {
    "path": "lua/dm5/detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- 漫本联盟 dm5.com\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\n\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.support.v7.widget.GridLayoutManager\"\nimport \"android.view.View\"\nimport \"android.support.v4.widget.Space\"\nimport \"androlua.widget.ninegride.LuaNineGridView\"\nimport \"androlua.widget.ninegride.LuaNineGridViewAdapter\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"androlua.widget.webview.WebViewActivity\"\n\n\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\nlocal log = require(\"log\")\nlocal screenWidth = uihelper.getScreenWidth()\n\nimport \"android.support.design.widget.CoordinatorLayout\"\nimport \"android.support.design.widget.AppBarLayout\"\nimport \"android.support.design.widget.CollapsingToolbarLayout\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"android.support.design.widget.FloatingActionButton\"\n\nlocal AppBarLayoutScrollingViewBehavior = import \"android.support.design.widget.AppBarLayout$ScrollingViewBehavior\"\n\n-- create view table\nlocal layout = {\n    CoordinatorLayout,\n    layout_width = \"match\",\n    layout_height = \"match\",\n    {\n        AppBarLayout,\n        id = \"appbar\",\n        layout_width = \"match\",\n        {\n            CollapsingToolbarLayout,\n            id = \"collapsing_toolbar\",\n            applayout_scrollFlags = 0x3,\n            background = \"#ffffff\",\n            layout_width = \"match\",\n            {\n                ImageView,\n                layout_width = \"match\",\n                layout_height = \"240dp\",\n                applayout_collapseMode = 2,\n                id = \"iv_cover\",\n                scaleType = \"centerCrop\",\n            },\n            {\n                View,\n                layout_width = \"match\",\n                layout_height = \"240dp\",\n                applayout_collapseMode = 2,\n                background = \"#22000000\",\n            },\n            {\n                LinearLayout,\n                layout_width = \"match\",\n                applayout_collapseMode = 1,\n                layout_marginTop = \"180dp\",\n                background = \"#ffffff\",\n                orientation = \"vertical\",\n                {\n                    FrameLayout,\n                    padding = \"16dp\",\n                    layout_width = \"match\",\n                    background = \"#2D2118\",\n                    {\n                        TextView,\n                        id = \"tv_title\",\n                        textSize = \"22sp\",\n                        textColor = \"#FFFFFF\",\n                    },\n                    {\n                        TextView,\n                        id = \"tv_updateinfo\",\n                        layout_marginTop = \"34dp\",\n                        textSize = \"14sp\",\n                        textColor = \"#FFFFFF\",\n                    },\n                    {\n                        TextView,\n                        id = \"tv_score\",\n                        layout_gravity = \"right\",\n                        layout_marginTop = \"8dp\",\n                        textSize = \"16sp\",\n                        textColor = \"#FFFFFF\",\n                    },\n                    {\n                        TextView,\n                        id = \"tv_type\",\n                        textSize = \"12sp\",\n                        layout_marginTop = \"60dp\",\n                        textColor = \"#EEFFFFFF\",\n                    },\n                },\n                {\n                    TextView,\n                    id = \"tv_desc\",\n                    padding = \"16dp\",\n                    textSize = \"14sp\",\n                    lineSpacingMultiplier = 1.3,\n                    textColor = \"#444444\",\n                    background = \"#ffffff\",\n                },\n            }\n        },\n    },\n    {\n        RecyclerView,\n        id = \"recyclerView\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        background = \"#ffffff\",\n        applayout_behavior = AppBarLayoutScrollingViewBehavior(),\n    },\n}\n\nlocal item_capter = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_height = \"60dp\",\n    gravity = \"center\",\n    {\n        TextView,\n        layout_height = \"match\",\n        layout_width = \"match\",\n        layout_margin = \"8dp\",\n        gravity = \"center\",\n        id = \"tv_chapter\",\n        textSize = \"13sp\",\n        textColor = \"#444444\",\n        background = \"#C5C8C0\",\n    },\n}\n\nlocal baseInfo = {}\nlocal data = {}\nlocal adapter\n\nlocal function trim(s)\n    return s:gsub(\"^%s+\", \"\"):gsub(\"%s+$\", \"\")\nend\n\nlocal function updateHeader()\n    -- header\n    LuaImageLoader.load(iv_cover, baseInfo.coverImg or '')\n    tv_title.setText(baseInfo.title or '')\n    tv_type.setText(string.format('%s        %s', trim(baseInfo.author), trim(baseInfo.type)))\n    tv_score.setText('评分:' .. baseInfo.score)\n    tv_desc.setText(baseInfo.desc or '')\n    tv_updateinfo.setText(baseInfo.updateInfo or '')\nend\n\nlocal function getData(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then\n            print('fetch dm5 data error')\n            return\n        end\n        uihelper.runOnUiThread(activity, function()\n            -- TOP10\n            local coverImg = string.match(body, '<div class=\"coverForm\".-<img src=\"(.-)\"')\n            local info = string.match(body, '<div class=\"info d[-]item[-]content\">(.-)</div>')\n            local title = string.match(info, '<p class=\"title d[-]nowrap\">(.-)</p>')\n            local updateInfo = string.match(info, '<p class=\"bottom d[-]nowrap\">(.-)</p>')\n            local author, type\n            for sub in string.gmatch(info, '<p class=\"subtitle d[-]nowrap\">(.-)</p>') do\n                if type == nil then\n                    type = sub\n                else\n                    author = sub\n                end\n            end\n            local score = string.match(body, '<div class=\"sorce\">(.-)</div>'):gsub('<.->', '')\n            local desc = string.match(body, '<div class=\"detailContent\">(.-)</div>'):gsub('<.->', '')\n            baseInfo.coverImg = coverImg\n            baseInfo.title = trim(title)\n            baseInfo.type = type:gsub('%s+', ' ')\n            baseInfo.author = author:gsub('%s+', ' ')\n            baseInfo.score = score:gsub('%s+', ' ')\n            baseInfo.updateInfo = updateInfo:gsub('%s+', ' ')\n            baseInfo.desc = trim(desc)\n            updateHeader()\n            local capters = string.match(body, '<div .-id=\"chapterList_1\".->(.-)</div>')\n            for li in string.gmatch(capters, '<li>(.-)</li>') do\n                local url = string.match(li, '<a href=\"(.-)\"')\n                local name = li:gsub('<.->', ''):gsub('%s+', '')\n                data[#data + 1] = { url = url, name = name }\n            end\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nfunction launchDetail(item)\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", \"dm5/viewer.lua\")\n    intent.putExtra(\"id\", item.url)\n    activity.startActivity(intent)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x00000000)\n    activity.setContentView(loadlayout(layout))\n\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            viewType = viewType + 1\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_capter, views, RecyclerView))\n            holder.itemView.setTag(views)\n            holder.itemView.getLayoutParams().width = screenWidth / 4\n            holder.itemView.onClick = function(view)\n                local p = holder.getAdapterPosition() + 1\n                launchDetail(data[p])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local views = holder.itemView.getTag()\n            if views == nil then return end\n            local item = data[position]\n            views.tv_chapter.setText(item.name or '')\n        end,\n    }))\n\n    recyclerView.setLayoutManager(GridLayoutManager(activity, 4))\n    recyclerView.setAdapter(adapter)\n\n    local url = activity.getIntent().getStringExtra('url')\n    getData(url or 'http://m.dm5.com/manhua-yongzheheluku/')\nend\n"
  },
  {
    "path": "lua/dm5/info.json",
    "content": "{\n  \"id\": \"pub.hanks.dm5\",\n  \"name\": \"动漫屋\",\n  \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fh10o351k7j20460460sh.jpg\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 2,\n  \"private\": true,\n  \"desc\": \"选自动漫屋（dm5）的漫画，可搜索\"\n}\n"
  },
  {
    "path": "lua/dm5/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- 漫本联盟 dm5.com\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\n\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.view.View\"\nimport \"android.support.v4.widget.Space\"\nimport \"androlua.widget.ninegride.LuaNineGridView\"\nimport \"androlua.widget.ninegride.LuaNineGridViewAdapter\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"androlua.widget.webview.WebViewActivity\"\n\n\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\nlocal log = require(\"log\")\nlocal screenWidth = uihelper.getScreenWidth()\n\nlocal category = {\n    \"原创精品\",\n    \"最新更新\",\n    \"热门连载\",\n    \"少年热血\",\n    \"少女爱情\",\n    \"最新上架\",\n    \"TOP10\",\n}\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    statusBarColor = \"#FDE04C\",\n    {\n        RelativeLayout,\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#FDE04C\",\n        {\n            TextView,\n            layout_centerInParent = true,\n            text = \"动漫屋\",\n            textColor = \"#43250C\",\n            textSize = \"18sp\",\n        },\n        {\n            ImageView,\n            id = \"iv_search\",\n            layout_width = \"56dp\",\n            layout_height = \"56dp\",\n            padding = \"16dp\",\n            layout_alignParentRight = true,\n            src = \"#dm5/ic_search.png\"\n        }\n    },\n    {\n        RecyclerView,\n        id = \"recyclerView\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n}\n\nlocal function launchSearch()\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", \"dm5/search.lua\")\n    activity.startActivity(intent)\nend\n\nlocal item_banner = {\n    FrameLayout,\n    layout_height = \"192dp\",\n    layout_width = \"match\",\n    {\n        ImageView,\n        layout_height = \"match\",\n        layout_width = \"match\",\n        id = \"iv_banner\",\n        scaleType = \"centerCrop\",\n    }\n}\n\nlocal item_title = {\n    RelativeLayout,\n    layout_height = \"48dp\",\n    paddingLeft = \"8dp\",\n    paddingRight = \"8dp\",\n    {\n        TextView,\n        id = \"tv_category\",\n        textSize = \"16sp\",\n        text = \"原创精品\",\n        textColor = \"#222222\",\n        layout_centerVertical = true,\n    },\n    {\n        TextView,\n        text = '更多﹥',\n        visibility = \"gone\",\n        layout_alignParentRight = true,\n        layout_centerVertical = true,\n    },\n}\n\nlocal ceil_category = {\n    LinearLayout,\n    layout_width = (screenWidth - uihelper.dp2px(8)) / 3,\n    layout_height = \"200dp\",\n    paddingLeft = \"4dp\",\n    paddingRight = \"4dp\",\n    orientation = \"vertical\",\n    {\n        ImageView,\n        layout_width = \"fill\",\n        layout_height = \"160dp\",\n        scaleType = \"centerCrop\",\n    },\n    {\n        TextView,\n        layout_height = \"match\",\n        layout_width = \"match\",\n        gravity = \"center\",\n    },\n}\n\nlocal item_topList = {\n    FrameLayout,\n    id = \"layout_top\",\n    layout_height = \"96dp\",\n    padding = \"8dp\",\n    {\n        ImageView,\n        id = \"iv_cover\",\n        layout_width = \"120dp\",\n        layout_height = \"80dp\",\n        scaleType = \"centerCrop\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_marginLeft = \"128dp\",\n        textColor = \"#444444\",\n        textSize = \"14sp\",\n    },\n    {\n        TextView,\n        id = \"tv_subtitle\",\n        layout_marginLeft = \"128dp\",\n        maxLines = 1,\n        textSize = \"12sp\",\n        textColor = \"#767676\",\n        layout_gravity = \"center_vertical\",\n    },\n    {\n        TextView,\n        id = \"tv_info\",\n        layout_marginLeft = \"128dp\",\n        textSize = \"12sp\",\n        textColor = \"#ec4646\",\n        layout_gravity = \"bottom\",\n    },\n    {\n        TextView,\n        id = \"tv_score\",\n        layout_gravity = \"right\",\n        textSize = \"10sp\",\n    },\n}\n\nlocal item_category = {\n    LinearLayout,\n    id = \"row\",\n    orientation = \"horizontal\",\n    paddingLeft = \"4dp\",\n    paddingRight = \"4dp\",\n    ceil_category,\n    ceil_category,\n    ceil_category,\n}\n\nlocal data_type = {\n    banner = 1,\n    title = 2,\n    category = 3,\n    top = 4,\n}\n\nlocal data = {}\nlocal adapter\n\nlocal function getData()\n    LuaHttp.request({ url = 'http://m.dm5.com/' }, function(error, code, body)\n        if error or code ~= 200 then\n            print('fetch dm5 data error')\n            return\n        end\n        uihelper.runOnUiThread(activity, function()\n            -- banner\n            local arr = {}\n            local ul = string.match(body, '<ul class=\"am[-]slides\">(.-)</ul>')\n            for url, img in string.gmatch(ul, '<a href=\"(.-)\"><img src=\"(.-)\"') do\n                if img:find('cdndm5.com') then\n                    arr[#arr + 1] = { url = url, img = img }\n                end\n            end\n            data[#data + 1] = { type = data_type.banner, data = arr }\n\n            -- 原创精品 最新更新 热门连载 少年热血 少女爱情 最新上架\n            local count = 1\n            local titleIndex = 1\n            arr = {}\n            for li in string.gmatch(body, '<li class=\"am[-]thumbnail\">(.-)</li>') do\n                local url, title = string.match(li, '<a href=\"(.-)\".-title=\"(.-)\">')\n                local img = string.match(li, '<img src=\"(.-)\"')\n                if url and title and img then\n                    local item = { url = url, title = title, img = img }\n\n                    if math.fmod(count - 1, 6) == 0 then\n                        data[#data + 1] = { type = data_type.title, data = category[titleIndex] }\n                        titleIndex = titleIndex + 1\n                    end\n                    if #arr == 3 then\n                        data[#data + 1] = { type = data_type.category, data = arr }\n                        arr = {}\n                    end\n                    arr[#arr + 1] = item\n                    count = count + 1\n                end\n            end\n\n            -- TOP10\n            data[#data + 1] = { type = data_type.title, data = category[titleIndex] }\n\n            local rankList = string.match(body, '<div class=\"rankList\">.-<ul class=\"list\">(.-)</ul>')\n            for li in string.gmatch(rankList, '<a .-</a>') do\n                local url, title = string.match(li, '<a href=\"(.-)\".-title=\"(.-)\">')\n                local img = string.match(li, '<img class=\"cover\" src=\"(.-)\"')\n                local subtitle = string.match(li, '<p class=\"subtitle d[-]nowrap\">(.-)</p>')\n                local updateInfo = string.match(li, '<span class=\"d[-]nowrap\">(.-)</span>')\n                local score = string.match(li, '<span class=\"score\">(.-)</span>')\n                if title and url and img then\n                    local item = { title = title, score = score, updateInfo = updateInfo, url = url, img = img, subtitle = subtitle }\n                    data[#data + 1] = { type = data_type.top, data = item }\n                end\n            end\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nfunction onDestroy()\n    LuaHttp.cancelAll()\nend\n\nlocal function launchDetail(url)\n    if url:find('^http://') == nil then\n        url = 'http://m.dm5.com' .. url\n    end\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'dm5/detail.lua')\n    intent.putExtra(\"url\", url)\n    activity.startActivity(intent)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    iv_search.onClick = launchSearch\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            position = position + 1\n            return data[position].type\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder\n            if viewType == data_type.banner then\n                holder = LuaRecyclerHolder(loadlayout(item_banner, views, RecyclerView))\n            elseif viewType == data_type.title then\n                holder = LuaRecyclerHolder(loadlayout(item_title, views, RecyclerView))\n            elseif viewType == data_type.category then\n                holder = LuaRecyclerHolder(loadlayout(item_category, views, RecyclerView))\n            else\n                holder = LuaRecyclerHolder(loadlayout(item_topList, views, RecyclerView))\n            end\n            holder.itemView.setTag(views)\n            holder.itemView.getLayoutParams().width = screenWidth\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            if item == nil or views == nil then return end\n            -- fill data\n            if item.type == data_type.banner then\n                LuaImageLoader.load(views.iv_banner, item.data[1].img)\n                views.iv_banner.onClick = function() launchDetail(item.data[1].url) end\n            elseif item.type == data_type.title then\n                views.tv_category.setText(item.data)\n            elseif item.type == data_type.category then\n                for i = 1, #item.data do\n                    local child = views.row.getChildAt(i - 1)\n                    LuaImageLoader.load(child.getChildAt(0), item.data[i].img)\n                    child.getChildAt(1).setText(item.data[i].title)\n                    child.onClick = function()\n                        launchDetail(item.data[i].url)\n                    end\n                end\n            elseif item.type == data_type.top then\n                LuaImageLoader.load(views.iv_cover, item.data.img)\n                views.tv_title.setText(item.data.title)\n                views.tv_subtitle.setText(item.data.subtitle)\n                views.tv_info.setText(item.data.updateInfo)\n                views.tv_score.setText(item.data.score)\n                views.layout_top.onClick = function()\n                    launchDetail(item.data.url)\n                end\n            end\n        end,\n    }))\n    recyclerView.setLayoutManager(LinearLayoutManager(activity))\n    recyclerView.setAdapter(adapter)\n    getData()\nend\n"
  },
  {
    "path": "lua/dm5/search.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- 漫本联盟 dm5.com\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\n\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.view.View\"\nimport \"android.support.v4.widget.Space\"\nimport \"androlua.widget.ninegride.LuaNineGridView\"\nimport \"androlua.widget.ninegride.LuaNineGridViewAdapter\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"androlua.widget.webview.WebViewActivity\"\n\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\nlocal log = require(\"log\")\nlocal screenWidth = uihelper.getScreenWidth()\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    statusBarColor = \"#FDE04C\",\n    {\n        RelativeLayout,\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#FDE04C\",\n        {\n            EditText,\n            id = \"et_keyword\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n            layout_marginLeft = \"16dp\",\n            layout_marginRight = \"64dp\",\n            maxLines = 1,\n            background = \"#00FDE04C\",\n            layout_centerInParent = true,\n            hint = \"请输入关键字\",\n            textColor = \"#43250C\",\n            textSize = \"16sp\",\n        },\n        {\n            ImageView,\n            id = \"iv_search\",\n            layout_width = \"56dp\",\n            layout_height = \"56dp\",\n            padding = \"16dp\",\n            layout_alignParentRight = true,\n            src = \"#dm5/ic_search.png\"\n        }\n    },\n    {\n        RecyclerView,\n        id = \"recyclerView\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n}\n\n\nlocal item_topList = {\n    FrameLayout,\n    id = \"layout_top\",\n    layout_height = \"96dp\",\n    padding = \"8dp\",\n    {\n        ImageView,\n        id = \"iv_cover\",\n        layout_width = \"120dp\",\n        layout_height = \"80dp\",\n        scaleType = \"centerCrop\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_marginLeft = \"128dp\",\n        textColor = \"#444444\",\n        textSize = \"14sp\",\n    },\n    {\n        TextView,\n        id = \"tv_subtitle\",\n        layout_marginLeft = \"128dp\",\n        maxLines = 1,\n        textSize = \"12sp\",\n        textColor = \"#767676\",\n        layout_gravity = \"center_vertical\",\n    },\n    {\n        TextView,\n        id = \"tv_info\",\n        layout_marginLeft = \"128dp\",\n        textSize = \"12sp\",\n        textColor = \"#ec4646\",\n        layout_gravity = \"bottom\",\n    },\n    {\n        TextView,\n        id = \"tv_score\",\n        layout_gravity = \"right\",\n        textSize = \"10sp\",\n    },\n}\n\n\nlocal page = 1\nlocal data = {}\nlocal adapter\nlocal lastKey = ''\n\nlocal function search()\n    -- search\n    local key = et_keyword.getText().toString()\n    local reset = false\n    if key ~= lastKey then\n        reset = true\n        lastKey = key\n        page = 1\n    end\n    local options = {\n        url = 'http://m.dm5.com/pagerdata.ashx',\n        method = \"POST\",\n        formData = {\n            \"t:7\",\n            \"f:0\",\n            \"pageindex:\" .. page,\n            \"title:\" .. key,\n        }\n    }\n    log.print_r(options)\n    LuaHttp.request(options, function(e, code, body)\n        if e or code ~= 200 then return end\n        local json = JSON.decode(body)\n        page = page + 1\n        uihelper.runOnUiThread(activity, function()\n            if reset then\n                for k, _ in pairs(data) do data[k] = nil end\n            end\n            for i = 1, #json do\n                data[#data + 1] = json[i]\n            end\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nfunction onDestroy()\n    LuaHttp.cancelAll()\nend\n\nlocal function launchDetail(url)\n    if url:find('^http://') == nil then\n        url = 'http://m.dm5.com' .. url\n    end\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'dm5/detail.lua')\n    intent.putExtra(\"url\", url)\n    activity.startActivity(intent)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    iv_search.onClick = search\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_topList, views, RecyclerView))\n            holder.itemView.setTag(views)\n            holder.itemView.getLayoutParams().width = screenWidth\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            if item == nil or views == nil then return end\n            log.print_r(item)\n            LuaImageLoader.load(views.iv_cover, item.Pic)\n            views.tv_title.setText(item.Title or 'xxxx')\n            views.tv_subtitle.setText(item.Categorys or '--')\n            views.tv_info.setText(item.LastUpdateInfo or '--')\n            views.tv_score.setText(item.Status or '--')\n            views.layout_top.onClick = function()\n                launchDetail(item.Url)\n            end\n\n            if position == #data then\n                search(true)\n            end\n        end,\n    }))\n    recyclerView.setLayoutManager(LinearLayoutManager(activity))\n    recyclerView.setAdapter(adapter)\nend\n"
  },
  {
    "path": "lua/dm5/viewer.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaWebView\"\n\n\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        ListView,\n        id = \"listview\",\n        dividerHeight = \"4dp\",\n        layouti_width = \"fill\",\n        layout_height = \"fill\",\n    },\n    {\n        LuaWebView,\n        id = \"webview\",\n        layout_height = 1,\n        layout_width = 1,\n        background = '#e1e1e1',\n    }\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    layout_height = \"560dp\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n}\n\nlocal data = {}\nlocal adapter\n\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html>\n<head>\n\t<title></title>\n\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n</head>\n<body>\n<script type=\"text/javascript\">\n%s\n</script>\n<script type=\"text/javascript\">\nvar s = {};\ns.method = 'setImg';\ns.data = newImgs;\nwindow.luaApp.call(JSON.stringify(s));\n</script>\n</body>\n</html>\n]]\nlocal function toast(s)\n    uihelper.runOnUiThread(activity, function()\n        activity.toast(s)\n    end)\nend\n\n\nlocal function getData(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local script = string.match(body, '<script type=\"text/javascript\">(.-)</script>')\n        local data = string.format(htmlTemplate, script)\n        uihelper.runOnUiThread(activity, function()\n            webview.loadData(data, \"text/html; charset=UTF-8\", nil)\n        end)\n    end)\nend\n\nlocal log = require('log')\nfunction launchDetail(item)\nend\n\nlocal function callback(jsonStr)\n    local json = JSON.decode(jsonStr)\n    if json.method ~= 'setImg' then\n        return\n    end\n\n    uihelper.runOnUiThread(activity, function()\n        for i = 1, #json.data do\n            data[#data + 1] = json.data[i]\n        end\n        adapter.notifyDataSetChanged()\n    end)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x00000000)\n    activity.setContentView(loadlayout(layout))\n\n    local id = activity.getIntent().getStringExtra('id')\n    local url = 'http://m.dm5.com' .. id\n\n    webview.injectObjectToJavascript(callback, \"luaApp\")\n\n    adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n        getCount = function() return #data end,\n        getView = function(position, convertView, parent)\n            position = position + 1 -- lua 索引从 1开始\n            if convertView == nil then\n                local views = {} -- store views\n                convertView = loadlayout(item_view, views, ListView)\n                convertView.getLayoutParams().width = parent.getWidth()\n                convertView.setTag(views)\n            end\n            local views = convertView.getTag()\n            local item = data[position]\n            print(position, item)\n            if item then\n                LuaImageLoader.load(views.iv_image, item, url)\n            end\n            return convertView\n        end\n    }))\n    listview.setAdapter(adapter)\n    listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n        onItemClick = function(adapter, view, position, id)\n        end,\n    }))\n\n\n    getData(url)\nend\n"
  },
  {
    "path": "lua/douban-daily/activity_news_detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nlocal uihelper = require \"uihelper\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#1CC4AD\",\n    {\n        LinearLayout,\n        orientation = \"horizontal\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#1CC4AD\",\n        gravity = \"center_vertical\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginLeft = \"8dp\",\n            scaleType = \"centerInside\",\n            src = \"@drawable/ic_menu_back\",\n        },\n        {\n            TextView,\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            singleLine = true,\n            textIsSelectable = true,\n            ellipsize = \"end\",\n            id = \"tv_title\",\n            gravity = \"center_vertical\",\n            paddingLeft = \"8dp\",\n            textColor = \"#ffffff\",\n            textSize = \"16sp\",\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            LuaWebView,\n            id = \"webview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal css = [[\n    article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-webkit-text-size-adjust:100%}body{font-family:'Helvetica Neue',Helvetica,Arial,Sans-serif;background:#fff;padding-top:0;margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0}h1,h2,h3,h4,h5,h6{font-size:16px}abbr[title]{border-bottom:1px dotted}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:\\201C\\201D\\2018\\2019}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0;vertical-align:middle;color:transparent;font-size:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}table{border-collapse:collapse;border-spacing:0;overflow:hidden}a{text-decoration:none}blockquote{border-left:3px solid #d0e5f2;font-style:normal;display:block;vertical-align:baseline;font-size:100%;margin:.5em 0;padding:0 0 0 1em}ul,ol{padding-left:20px}.content{color:#444;line-height:1.6em;font-size:16px;margin:16px}.content img{max-width:100%;display:block;margin:30px auto}.content img+img{margin-top:15px}.content img[src*=\"zhihu.com/equation\"]{display:inline-block;margin:0 3px}.content a{color:#259}.content a:hover{text-decoration:underline}\n]]\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html>\n<head>\n    <title></title>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width; initial-scale=1; minimum-scale=1; maximum-scale=2\">\n    <meta content=\"width=device-width,user-scalable=no\" name=\"viewport\">\n    <style type=\"text/css\"> %s </style>\n</head>\n<body>\n<div class=\"content\"> %s </div>\n<script type=\"text/javascript\">\nfunction openImgActivity(a,b){var c=JSON.stringify({currentIndex:b,uris:a});var d=\"hydrogen://pub.hydrogen.android?action=open_img&data=\"+c;var e=document.createElement(\"iframe\");e.src=d;e.style.display=\"none\";document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},2000)}function init(){var a=document.querySelectorAll(\".content img\");for(var b=0;b<a.length;b++){a[b].addEventListener(\"click\",function(g){var e=g.target||g.srcElement;var c=[];var d=0;var h=document.querySelectorAll(\".content img\");for(var f=0;f<h.length;f++){c[f]=h[f].getAttribute(\"src\");if(e.getAttribute(\"src\").indexOf(c[f])!=-1){d=f}}openImgActivity(c,d)})}}init();\n</script>\n</body>\n</html>\n]]\n\n\n\nlocal function getData(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local content = string.match(body, '<main class=\"container.->(.-)</main>'):gsub('style=\".-\"', ''):gsub('width=%d+', ''):gsub('height=%d+', '')\n        local data = string.format(htmlTemplate, css, content)\n        uihelper.runOnUiThread(activity, function()\n            webview.loadData(data, \"text/html; charset=UTF-8\", nil)\n        end)\n    end)\nend\n\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    back.onClick = function()\n        activity.finish()\n    end\n    local url = activity.getIntent().getStringExtra('url')\n    tv_title.setText(url)\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    getData(url)\nend\n\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend\n"
  },
  {
    "path": "lua/douban-daily/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.os.Build\"\nlocal Orientation = import \"android.graphics.drawable.GradientDrawable$Orientation\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal imageWidth = uihelper.getScreenWidth() - uihelper.dp2px(32)\nlocal colors = luajava.createArray(\"int\", { 0x77000000, 0x00000000 })\nlocal gd = GradientDrawable(Orientation.TOP_BOTTOM, colors)\ngd.setCornerRadius(uihelper.dp2px(3))\n\nlocal function getData(params, data, adapter, fragment, swipe_layout, reload)\n    local url = string.format('https://api.qingmang.me/v2/article.list?token=c400a7e21688496ca3e7f17c6b0d1846&category_id=%s', params.rid)\n    if params.nextUrl then url = params.nextUrl end\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then return end\n        local json = JSON.decode(body)\n        if json.hasMore and json.nextUrl then params.nextUrl = json.nextUrl end\n        local arr = json.articles\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                for k, _ in pairs(date) do data[k] = nil end\n            end\n            local s = #data\n            for i = 1, #arr do\n                local item = arr[i]\n                if item.images and #item.images > 0 then\n                    item.img = item.images[1].url .. '?imageMogr2/quality/95'\n                    item.calcHeight = math.floor(imageWidth * tonumber(item.images[1].height) / tonumber(item.images[1].width))\n                end\n                data[#data + 1] = item\n            end\n            adapter.notifyDataSetChanged()\n            swipe_layout.setRefreshing(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, item)\n    local activity = fragment.getActivity()\n    if item == nil or item.contentUrl == nil then\n        activity.toast('没有 url 可以打开')\n        return\n    end\n    local activity = fragment.getActivity()\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'douban-daily/activity_news_detail.lua')\n    intent.putExtra(\"url\", item.contentUrl)\n    activity.startActivity(intent)\nend\n\nlocal function newInstance(rid)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            ListView,\n            id = \"listview\",\n            background = '#FFFFFF',\n            dividerHeight = 0,\n            paddingTop = \"16dp\",\n            clipToPadding = false,\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        LinearLayout,\n        background = '#ffffff',\n        orientation = 'vertical',\n        layout_width = \"fill\",\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_marginLeft = '16dp',\n            layout_marginRight = '16dp',\n            layout_width = \"fill\",\n            layout_height = \"200dp\",\n            scaleType = \"centerCrop\",\n        },\n\n        {\n            TextView,\n            id = \"tv_title\",\n            layout_width = \"fill\",\n            layout_marginLeft = '16dp',\n            layout_marginRight = '16dp',\n            layout_marginTop = '8dp',\n            maxLines = 2,\n            lineSpacingMultiplier = 1.3,\n            textSize = \"16sp\",\n            textColor = \"#222222\",\n        },\n        {\n            TextView,\n            id = \"tv_desc\",\n            layout_width = \"fill\",\n            layout_marginTop = '8dp',\n            layout_marginLeft = '16dp',\n            layout_marginRight = '16dp',\n            layout_marginBottom = '16dp',\n            maxLines = 4,\n            lineSpacingMultiplier = 1.3,\n            textSize = \"12sp\",\n            textColor = \"#666666\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"16dp\",\n        }\n    }\n\n\n    local hadLoadData\n    local isVisible\n    local lastId\n    local params = { rid = rid }\n    local data = {}\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(params, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        convertView.getLayoutParams().width = parent.getWidth()\n                        convertView.setTag(views)\n                    end\n                    local views = convertView.getTag()\n                    local item = data[position]\n                    if item then\n                        if item.img then\n                            views.iv_image.setVisibility(0)\n                            LuaImageLoader.loadWithRadius(views.iv_image, 3, item.img)\n                            views.iv_image.getLayoutParams().height = item.calcHeight\n                        else\n                            views.iv_image.setVisibility(8)\n                        end\n                        views.tv_title.setText(item.title or 'ERROR TITLE')\n                        views.tv_desc.setText(item.snippet or '')\n                    end\n                    if position == #data then getData(params, data, adapter, fragment, ids.swipe_layout) end\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    launchDetail(fragment, data[position + 1])\n                end,\n            }))\n            ids.swipe_layout.setRefreshing(true)\n            ids.swipe_layout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    getData(params, data, adapter, fragment, ids.swipe_layout, true)\n                end\n            }))\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/douban-daily/info.json",
    "content": "{\n  \"id\": \"pub.hanks.douban-daily\",\n  \"name\": \"豆瓣一刻\",\n  \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fhlllrrhr0j2046046jr8.jpg\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0\",\n  \"versionCode\": 1,\n  \"private\": true,\n  \"desc\": \"豆瓣一刻\"\n}\n"
  },
  {
    "path": "lua/douban-daily/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\n\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal fragmentNews = require \"douban-daily/fragment_news\"\n\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#1CC4AD\",\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#1CC4AD\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\n\ntable.insert(data.fragments, fragmentNews.newInstance('p38'))\ntable.insert(data.titles, '今日一刻')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3401'))\ntable.insert(data.titles, '热门精选')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3363'))\ntable.insert(data.titles, '打鸡血')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3367'))\ntable.insert(data.titles, '洗洗睡')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p15913'))\ntable.insert(data.titles, '爱美丽')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3369'))\ntable.insert(data.titles, '闲翻书')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3371'))\ntable.insert(data.titles, '看电影')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3373'))\ntable.insert(data.titles, '听音乐')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3375'))\ntable.insert(data.titles, '聊艺术')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3379'))\ntable.insert(data.titles, '哈哈哈')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3381'))\ntable.insert(data.titles, '假日厨房')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3383'))\ntable.insert(data.titles, '食记')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3387'))\ntable.insert(data.titles, '生活家')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3389'))\ntable.insert(data.titles, '去远方')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3391'))\ntable.insert(data.titles, '海外志')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3393'))\ntable.insert(data.titles, '冷知识')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3395'))\ntable.insert(data.titles, '萌')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3397'))\ntable.insert(data.titles, '连载')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p3399'))\ntable.insert(data.titles, '鬼敲门')\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    viewPager.setAdapter(adapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\n    tab.setSelectedTabIndicatorColor(0xffffffff)\n    tab.setTabTextColors(0x88ffffff, 0xffffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n"
  },
  {
    "path": "lua/doubanmovie/detail.lua",
    "content": "require \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nlocal JSON = require \"cjson\"\nlocal uihelper = require \"uihelper\"\n\nlocal layout = {\n    ScrollView,\n    layout_width = \"fill\",\n    layout_height = \"wrap\",\n    {\n        LinearLayout,\n        layout_width = \"fill\",\n        layout_height = \"wrap\",\n        orientation = \"vertical\",\n        background = \"#FFFFFF\",\n        {\n            FrameLayout,\n            layout_width = \"fill\",\n            layout_height = \"300dp\",\n            {\n                ImageView,\n                id = \"iv_bg\",\n                layout_width = \"fill\",\n                scaleType = \"centerCrop\",\n                layout_height = \"220dp\",\n            },\n            {\n                View,\n                layout_width = \"fill\",\n                layout_height = \"220dp\",\n                background = \"#88000000\",\n            },\n            {\n                ImageView,\n                id = \"iv_cover\",\n                layout_gravity = \"bottom\",\n                layout_marginLeft = \"16dp\",\n                layout_marginBottom = \"8dp\",\n                layout_width = \"104dp\",\n                layout_height = \"160dp\",\n                scaleType = \"centerCrop\",\n                background = \"@drawable/ic_loading\",\n                elevation = \"2dp\",\n            },\n            {\n                View,\n                layout_gravity = \"bottom\",\n                layout_marginLeft = \"16dp\",\n                layout_marginBottom = \"8dp\",\n                layout_width = \"104dp\",\n                layout_height = \"160dp\",\n                elevation = \"2dp\",\n                background = \"#44000000\",\n            },\n            {\n                ImageView,\n                layout_gravity = \"bottom\",\n                layout_marginLeft = \"16dp\",\n                layout_marginBottom = \"8dp\",\n                layout_width = \"104dp\",\n                layout_height = \"160dp\",\n                padding = \"35dp\",\n                elevation = \"2dp\",\n                scaleType = \"centerInside\",\n                src = \"#doubanmovie/ic_video_play.png\",\n            },\n            {\n                RelativeLayout,\n                layout_width = \"fill\",\n                layout_height = \"164dp\",\n                layout_gravity = \"bottom\",\n                layout_marginRight = \"16dp\",\n                layout_marginLeft = \"136dp\",\n                layout_marginBottom = \"4dp\",\n                {\n                    TextView,\n                    id = \"tv_title\",\n                    layout_width = \"fill\",\n                    textColor = \"#faffffff\",\n                    textSize = \"20sp\",\n                },\n                {\n                    TextView,\n                    layout_below = \"tv_title\",\n                    id = \"tv_rate\",\n                    layout_width = \"fill\",\n                    textColor = \"#faffffff\",\n                    textSize = \"16sp\",\n                    layout_marginTop = \"4dp\",\n                },\n                {\n                    TextView,\n                    id = \"tv_year\",\n                    layout_marginTop = \"4dp\",\n                    layout_alignParentBottom = true,\n                    layout_width = \"fill\",\n                    textSize = \"14sp\",\n                    textColor = \"#8a8a8a\"\n                },\n\n                {\n                    TextView,\n                    id = \"tv_directors\",\n                    layout_marginTop = \"4dp\",\n                    layout_width = \"fill\",\n                    textSize = \"14sp\",\n                    layout_above = \"tv_year\",\n                    textColor = \"#8a8a8a\"\n                },\n\n                {\n                    TextView,\n                    id = \"tv_genres\",\n                    layout_width = \"fill\",\n                    layout_marginTop = \"4dp\",\n                    textSize = \"14sp\",\n                    textColor = \"#8a8a8a\",\n                    layout_above = \"tv_directors\",\n                },\n\n                {\n                    TextView,\n                    id = \"tv_duration\",\n                    layout_width = \"fill\",\n                    textColor = \"#00ffffff\",\n                    textSize = \"14sp\",\n                    layout_marginTop = \"4dp\",\n                    layout_above = \"tv_genres\",\n                },\n            },\n        },\n        {\n            TextView,\n            textSize = \"20sp\",\n            text = \"剧情简介\",\n            textColor = \"#444444\",\n            layout_margin = \"16dp\",\n        },\n        {\n            TextView,\n            id = \"tv_summary\",\n            textSize = \"12sp\",\n            layout_marginLeft = \"16dp\",\n            layout_marginRight = \"16dp\",\n            lineSpacingMultiplier = 1.5,\n            textColor = \"#777777\",\n        },\n        {\n            View,\n            layout_margin = \"16dp\",\n            layout_height = 2,\n            background = \"#f1f1f1\",\n        },\n        {\n            TextView,\n            layout_margin = \"16dp\",\n            textSize = \"20sp\",\n            text = \"剧照\",\n            textColor = \"#444444\",\n        },\n        {\n            HorizontalScrollView,\n            layout_marginBottom = \"16dp\",\n            {\n                LinearLayout,\n                id = \"layout_casts\",\n                layout_width = \"fill\",\n                layout_height = \"120dp\",\n                paddingLeft = \"16dp\",\n                clipToPadding = false,\n            }\n        },\n        {\n            TextView,\n            layout_margin = \"16dp\",\n            textSize = \"20sp\",\n            text = \"热门评论\",\n            textColor = \"#444444\",\n        },\n        {\n            LinearLayout,\n            id = \"layout_comment\",\n            layout_width = \"fill\",\n            orientation = \"vertical\",\n        }\n    },\n}\n\nlocal item_comment = {\n    RelativeLayout,\n    layout_width = \"fill\",\n    paddingLeft = \"16dp\",\n    paddingRight = \"16dp\",\n    paddingTop = \"16dp\",\n    {\n        ImageView,\n        id = \"iv_avatar\",\n        layout_width = \"36dp\",\n        layout_height = \"36dp\",\n        scaleType = \"centerCrop\",\n    },\n    {\n        TextView,\n        id = \"tv_nick\",\n        layout_width = \"fill\",\n        textColor = \"#111111\",\n        textSize = \"15sp\",\n        layout_marginLeft = \"48dp\",\n    },\n\n    {\n        TextView,\n        id = \"tv_content\",\n        layout_width = \"fill\",\n        textColor = \"#222222\",\n        textSize = \"13sp\",\n        layout_below = \"tv_nick\",\n        layout_marginLeft = \"48dp\",\n        layout_marginTop = \"8dp\",\n        lineSpacingMultiplier = 1.2,\n    },\n    {\n        View,\n        layout_below = \"tv_content\",\n        layout_marginTop = \"16dp\",\n        layout_marginLeft = \"48dp\",\n        layout_width = \"fill\",\n        layout_height = \"1dp\",\n        background = \"#f1f1f1\",\n    },\n}\n\nlocal item_cast = {\n    LinearLayout,\n    layout_width = \"168dp\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    gravity = \"center\",\n    paddingRight = \"8dp\",\n    {\n        ImageView,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        scaleType = \"centerCrop\",\n    },\n}\n\nlocal function updateHeader(movie)\n    uihelper.runOnUiThread(activity, function()\n        local imgUrl = movie.img:gsub(\"w.h\",\"148.208\")\n        LuaImageLoader.load(iv_bg, imgUrl)\n        LuaImageLoader.load(iv_cover, imgUrl)\n        local rate = movie.sc\n        if rate == '0' or rate == 0 then rate = '暂无' end\n        tv_title.setText(movie.nm)\n        tv_rate.setText('评分:  ' .. rate)\n        tv_summary.setText(movie.dra or '暂无简介')\n        tv_year.setText('上映时间:  ' .. movie.rt or '')\n        tv_genres.setText('分类:  ' .. movie.cat)\n        tv_duration.setText(string.format('%s/%s分钟', movie.src or '未知', movie.pn))\n        tv_directors.setText('导演:  ' .. movie.dir)\n        if movie.vd then\n            iv_cover.onClick = function(view)\n                local json = { url = movie.vd, poster = movie.img }\n                VideoPlayerActivity.start(activity, JSON.encode(json))\n            end\n        end\n\n        if movie.photos then\n            layout_casts.removeAllViews()\n            for i = 1, #movie.photos do\n                local img = movie.photos[i]:gsub('net/.-/movie', 'net/800.1600/movie')\n                local child = loadlayout(item_cast)\n                LuaImageLoader.load(child.getChildAt(0), img)\n                layout_casts.addView(child)\n            end\n        end\n    end)\nend\n\nlocal function updateComment(comments)\n    uihelper.runOnUiThread(activity, function()\n\n        layout_comment.removeAllViews()\n        for i = 1, #comments do\n            local views = {}\n            local child = loadlayout(item_comment, views)\n            LuaImageLoader.load(views.iv_avatar, comments[i].avatarUrl)\n            views.tv_nick.setText(comments[i].nick or '')\n            views.tv_content.setText(comments[i].content or '')\n            layout_comment.addView(child)\n        end\n    end)\nend\n\nlocal function getData(id)\n    local url = string.format('http://m.maoyan.com/ajax/detailmovie?movieId=%d', id)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then\n            print('get data error ' .. code)\n        end\n        local json = JSON.decode(body)\n        local movie = json.detailMovie\n        if movie then updateHeader(movie) end\n    end)\n\n    local commentUrl = string.format('http://m.maoyan.com/review/v2/comments.json?movieId=%d&userId=-1&offset=0&limit=15&ts=0&type=3',id)\n    LuaHttp.request({ url = commentUrl }, function(error, code, body)\n        if error or code ~= 200 then\n            print('get data error ' .. code)\n        end\n        local json = JSON.decode(body)\n        local comments = json.data.hotComments -- 热门\n        if comments then updateComment(comments) end\n    end)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x00000000)\n    activity.setContentView(loadlayout(layout))\n    local id = activity.getIntent().getStringExtra('id')\n    getData(id)\nend\n"
  },
  {
    "path": "lua/doubanmovie/info.json",
    "content": "{\n  \"id\": \"pub.hanks.doubanmovie\",\n  \"name\": \"热映电影\",\n  \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fh34zfgjcvj2046046weh.jpg\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.2\",\n  \"versionCode\": 5,\n  \"desc\": \"展示最近热映电影，可看预告片\"\n}\n"
  },
  {
    "path": "lua/doubanmovie/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- douban - hot movie\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.GridLayoutManager\"\n\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\nlocal log = require(\"log\")\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    statusBarColor = \"#DB3C2E\",\n    {\n        TextView,\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#DB3C2E\",\n        gravity = \"center\",\n        text = \"热映电影\",\n        textColor = \"#FFFFFF\",\n        textSize = \"18sp\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            RecyclerView,\n            id = \"recyclerView\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n            paddingTop = \"8dp\",\n            paddingLeft = \"4dp\",\n            paddingRight = \"4dp\",\n            clipToPadding = false,\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"match\",\n    padding = \"4dp\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"168dp\",\n        scaleType = \"centerCrop\",\n    },\n    {\n        View,\n        layout_width = \"fill\",\n        layout_height = \"36dp\",\n        background = \"#AA000000\",\n        layout_gravity = \"bottom\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_height = \"36dp\",\n        layout_width = \"fill\",\n        gravity = \"center_vertical\",\n        layout_gravity = \"bottom\",\n        paddingLeft = \"28dp\",\n        textSize = \"12sp\",\n        maxLines = 1,\n        ellipsize = \"end\",\n        textColor = \"#FFFFFF\",\n    },\n    {\n        TextView,\n        id = \"tv_score\",\n        layout_height = \"36dp\",\n        paddingLeft = \"4dp\",\n        gravity = \"center_vertical\",\n        layout_gravity = \"bottom\",\n        textSize = \"13sp\",\n        textColor = \"#F9B600\",\n    },\n}\n\n\nlocal data = {}\nlocal adapter\n\nfunction getData()\n    local url = string.format('http://m.maoyan.com/ajax/movieOnInfoList')\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then\n            print('fetch data error')\n            return\n        end\n        print(body)\n        local arr = JSON.decode(body).movieList\n        uihelper.runOnUiThread(activity, function()\n            for i = 1, #arr do\n                data[#data + 1] = arr[i]\n            end\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nlocal function launchDetail(item)\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'doubanmovie/detail.lua')\n    intent.putExtra(\"id\", item.id .. '')\n    activity.startActivity(intent)\nend\n\n\nfunction onDestroy()\n    LuaHttp.cancelAll()\nend\n\n\nfunction onCreate(savedInstanceState)\n    activity.setLightStatusBar()\n    activity.setContentView(loadlayout(layout))\n    local screenWidth = uihelper.getScreenWidth()\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder\n            holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.setTag(views)\n            holder.itemView.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1\n            end\n            holder.itemView.getLayoutParams().width = screenWidth / 3\n            holder.itemView.onClick = function()\n                local p = holder.getAdapterPosition() + 1\n                launchDetail(data[p])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local views = holder.itemView.getTag()\n            if views == nil then return end\n            local item = data[position]\n            if item then\n                local imgUrl = item.img:gsub(\"w.h\",\"148.208\")\n                print(imgUrl)\n                LuaImageLoader.load(views.iv_image, imgUrl)\n                views.tv_title.setText(item.nm)\n                local sc = item.sc\n                if sc == nil or sc == 0 then sc = '' end\n                views.tv_score.setText('' .. sc)\n            end\n        end,\n    }))\n    recyclerView.setLayoutManager(GridLayoutManager(activity, 3))\n    recyclerView.setAdapter(adapter)\n    getData()\nend\n"
  },
  {
    "path": "lua/douyu/detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nlocal uihelper = require(\"uihelper\")\n-- create view table\nlocal layout = {\n    FrameLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        LuaWebView,\n        id = \"webview\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    }\n}\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x00000000)\n    activity.setContentView(loadlayout(layout))\n    local url = activity.getIntent().getStringExtra('url')\n    webview.loadUrl(url)\nend\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend"
  },
  {
    "path": "lua/douyu/info.json",
    "content": "{\n  \"id\": \"pub.hanks.douyu\",\n  \"name\": \"斗鱼直播\",\n  \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fj45bhugy4j2046046q2s.jpg\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.0\",\n  \"versionCode\": 1,\n  \"desc\": \"斗鱼直播\"\n}\n"
  },
  {
    "path": "lua/douyu/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- 漫本联盟 dm5.com\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\n\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.view.View\"\nimport \"android.support.v4.widget.Space\"\nimport \"androlua.widget.ninegride.LuaNineGridView\"\nimport \"androlua.widget.ninegride.LuaNineGridViewAdapter\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"android.support.design.widget.CoordinatorLayout\"\nimport \"pub.hydrogen.android.R\"\nimport \"android.net.Uri\"\n\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\nlocal log = require(\"log\")\nlocal screenWidth = uihelper.getScreenWidth()\nactivity.setTheme(R.style.Theme_AppCompat_NoActionBar)\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    statusBarColor = \"#fe7b09\",\n    {\n        Toolbar,\n        background = '#fe7b09',\n        id = 'toolbar',\n        layout_width = \"match\",\n        layout_height = \"56dp\",\n        titleTextColor = \"#ffffff\",\n    },\n    {\n        RecyclerView,\n        background = '#ffffff',\n        id = \"recyclerView\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n}\n\nlocal item_banner = {\n    FrameLayout,\n    layout_height = \"142dp\",\n    layout_width = \"match\",\n    {\n        ImageView,\n        layout_height = \"match\",\n        layout_width = \"match\",\n        id = \"iv_banner\",\n        scaleType = \"centerCrop\",\n    }\n}\n\nlocal item_title = {\n    RelativeLayout,\n    layout_height = \"48dp\",\n    { View, layout_width = \"4dp\", layout_height = \"24dp\", background = '#fe7b09', layout_centerVertical = true },\n    { TextView, paddingLeft = \"8dp\", id = \"tv_category\", textSize = \"18sp\", text = \"原创\", textColor = \"#222222\", layout_centerVertical = true, },\n    { TextView, text = '更多﹥', layout_alignParentRight = true, layout_centerVertical = true, textColor = '#888888', paddingRight = '8dp' },\n}\n\nlocal ceil_category = {\n    LinearLayout,\n    layout_width = (screenWidth - uihelper.dp2px(4)) / 2,\n    orientation = \"vertical\",\n    {\n        ImageView,\n        layout_width = \"fill\",\n        layout_height = \"120dp\",\n        scaleType = \"centerCrop\",\n    },\n    {\n        TextView,\n        layout_height = \"36dp\",\n        layout_width = \"match\",\n        singleLine = true,\n        maxLines = 1,\n        paddingLeft = '4dp',\n        ellipsize = 'end',\n        textColor = '#000000',\n        gravity = \"center_vertical\",\n    },\n}\n\nlocal item_video = {\n    LinearLayout,\n    id = \"row\",\n    layout_width = \"fill\",\n    orientation = \"horizontal\",\n    ceil_category,\n    { View, layout_width = \"4dp\", layout_height = 1 },\n    ceil_category,\n}\n\nlocal data_type = {\n    banner = 1,\n    title = 2,\n    video = 3,\n}\n\nlocal data = {}\n\nlocal adapter\n\nlocal function getData()\n    LuaHttp.request({ url = 'https://m.douyu.com/api/home/mix' }, function(error, code, body)\n        if error or code ~= 200 then\n            print('fetch douyu data error')\n            return\n        end\n        local json = JSON.decode(body)\n        uihelper.runOnUiThread(activity, function()\n            if json == nil then\n                return\n            end\n            -- banner\n            if json.banner and #json.banner > 0 then\n                data[#data + 1] = { type = data_type.banner, banner = json.banner }\n            end\n\n            if json.hotList and #json.hotList > 0 then\n                data[#data + 1] = { type = data_type.title, title = '最热', room_id = 'https://m.douyu.com/list/index' }\n                local item = json.hotList[1]\n                for j = 1, #item.data, 2 do\n                    if j < #item.data then\n                        data[#data + 1] = { type = data_type.video, data = { item.data[j], item.data[j + 1] } }\n                    end\n                end\n            end\n\n            if json.liveList and #json.liveList > 0 then\n                data[#data + 1] = { type = data_type.title, title = '正在直播', room_id = 'https://m.douyu.com/list/index' }\n                for i = 1, #json.liveList, 2 do\n                    if i < #json.liveList then\n                        data[#data + 1] = { type = data_type.video, data = { json.liveList[i], json.liveList[i + 1] } }\n                    end\n                end\n            end\n\n            if json.yzList and #json.yzList > 0 then\n                data[#data + 1] = { type = data_type.title, title = '颜值', room_id = 'https://m.douyu.com/roomlists/yz' }\n                for i = 1, #json.yzList, 2 do\n                    if i < #json.yzList then\n                        data[#data + 1] = { type = data_type.video, data = { json.yzList[i], json.yzList[i + 1] } }\n                    end\n                end\n            end\n            if json.mixList and #json.mixList > 0 then\n                for i = 1, #json.mixList do\n                    local item = json.mixList[i]\n                    data[#data + 1] = { type = data_type.title, title = item.tabName, room_id = 'https://m.douyu.com/list/custom/' .. item.shortName }\n                    for j = 1, #item.data, 2 do\n                        if j < #item.data then\n                            data[#data + 1] = { type = data_type.video, data = { item.data[j], item.data[j + 1] } }\n                        end\n                    end\n                end\n            end\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nfunction onDestroy()\n    LuaHttp.cancelAll()\nend\n\nlocal function launchDetail(item)\n    local url = item.room_id\n    if type(url) == 'number' or not url:find(\"^http\") then\n        url = string.format('https://m.douyu.com/%d', url)\n    end\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'douyu/detail.lua')\n    print(url)\n    intent.putExtra(\"url\", url)\n    activity.startActivity(intent)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    activity.setSupportActionBar(toolbar)\n    activity.setTitle('斗鱼直播')\n    toolbar.setNavigationIcon(LuaDrawable.create('douyu/douyu.png'))\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            position = position + 1\n            return data[position].type\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder\n            if viewType == data_type.banner then\n                holder = LuaRecyclerHolder(loadlayout(item_banner, views, RecyclerView))\n            elseif viewType == data_type.title then\n                holder = LuaRecyclerHolder(loadlayout(item_title, views, RecyclerView))\n            elseif viewType == data_type.video then\n                holder = LuaRecyclerHolder(loadlayout(item_video, views, RecyclerView))\n            end\n            holder.itemView.setTag(views)\n            holder.itemView.getLayoutParams().width = screenWidth\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            if item == nil or views == nil then return end\n            -- fill data\n            if item.type == data_type.banner then\n                LuaImageLoader.load(views.iv_banner, item.banner[1].pic_url)\n                views.iv_banner.onClick = function() launchDetail(item.banner[1].room) end\n            elseif item.type == data_type.title then\n                views.tv_category.setText(item.title)\n                holder.itemView.onClick = function()\n                    launchDetail(item)\n                end\n            elseif item.type == data_type.video then\n                local child1 = views.row.getChildAt(0)\n                local child2 = views.row.getChildAt(2)\n                LuaImageLoader.load(child1.getChildAt(0), item.data[1].room_src)\n                LuaImageLoader.load(child2.getChildAt(0), item.data[2].room_src)\n                child1.getChildAt(1).setText(item.data[1].room_name)\n                child2.getChildAt(1).setText(item.data[2].room_name)\n                child1.onClick = function()\n                    launchDetail(item.data[1])\n                end\n                child2.onClick = function()\n                    launchDetail(item.data[2])\n                end\n            end\n        end,\n    }))\n    recyclerView.setLayoutManager(LinearLayoutManager(activity))\n    recyclerView.setAdapter(adapter)\n    getData()\nend\n\nfunction onCreateOptionsMenu(menu)\n    menu.add(\"网页版\")\n    return true\nend\n\nfunction onOptionsItemSelected(item)\n    local title = item.getTitle()\n    if title == \"网页版\" then\n        activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse('http://m.douyu.com')))\n    end\nend\n"
  },
  {
    "path": "lua/eyepetizer/info.json",
    "content": "{\n  \"id\": \"pub.hanks.eyepetizer\",\n  \"name\": \"开眼\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088bc73fd882a?w=150&h=150&f=png&s=2157\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 3,\n  \"desc\": \"每日开眼视频精选\"\n}\n"
  },
  {
    "path": "lua/eyepetizer/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\n\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    statusBarColor = \"#F0000000\",\n    {\n        TextView,\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#F0000000\",\n        gravity = \"center\",\n        text = \"Eyepetizer\",\n        textColor = \"#AAffffff\",\n        textSize = \"18sp\",\n    },\n    {\n        ListView,\n        id = \"listview\",\n        dividerHeight = 0,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    layout_height = \"240dp\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        scaleType = \"centerCrop\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        background = \"#66000000\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        padding = \"32dp\",\n        gravity = \"center\",\n        maxLines = \"5\",\n        lineSpacingMultiplier = '1.2',\n        textSize = \"14sp\",\n        textColor = \"#CCFFFFFF\",\n    },\n}\n\n\nlocal data = {\n    dailyList = {}\n}\nlocal adapter\n\nlocal function getData()\n    -- http://baobab.kaiyanapp.com/api/v1/feed\n    local url = data.nextPageUrl\n    if url == nil then url = 'http://baobab.kaiyanapp.com/api/v1/feed?udid=3e7ee30c6fc0004a773dc33b0597b5732b145c04' end\n    if url:find('udid=') == nil then url = url .. '&udid=3e7ee30c6fc0004a773dc33b0597b5732b145c04' end\n    print(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then\n            print('fetch data error')\n            return\n        end\n        local str = JSON.decode(body)\n        uihelper.runOnUiThread(activity, function()\n            data.nextPageUrl = str.nextPageUrl\n            local list = str.dailyList[1].videoList\n            for i = 1, #list do\n                data.dailyList[#data.dailyList + 1] = list[i]\n            end\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nlocal function launchDetail(item)\n    local json = { url = item.playInfo[#item.playInfo].url, poster = item.coverForDetail }\n    VideoPlayerActivity.start(activity, JSON.encode(json))\nend\n\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0xF0000000)\n    activity.setContentView(loadlayout(layout))\n    adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n        getCount = function() return #data.dailyList end,\n        getItem = function(position) return nil end,\n        getItemId = function(position) return position end,\n        getView = function(position, convertView, parent)\n            position = position + 1 -- lua 索引从 1开始\n            if position == #data.dailyList then\n                getData()\n            end\n            if convertView == nil then\n                local views = {} -- store views\n                convertView = loadlayout(item_view, views, ListView)\n                if parent then\n                    local params = convertView.getLayoutParams()\n                    params.width = parent.getWidth()\n                end\n                convertView.setTag(views)\n            end\n            local views = convertView.getTag()\n            local item = data.dailyList[position]\n            if item then\n                LuaImageLoader.load(views.iv_image, item.coverForFeed)\n                views.tv_title.setText(item.title)\n            end\n            return convertView\n        end\n    }))\n    listview.setAdapter(adapter)\n    listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n        onItemClick = function(adapter, view, position, id)\n            launchDetail(data.dailyList[position + 1])\n        end,\n    }))\n    getData()\nend\n"
  },
  {
    "path": "lua/gacha/info.json",
    "content": "{\n  \"id\": \"pub.hanks.gacha\",\n  \"name\": \"网易插画\",\n  \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fhaaa8qcofj2046046we9.jpg\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0\",\n  \"versionCode\": 1,\n  \"private\": true,\n  \"desc\": \"网易每日插画排行\"\n}\n"
  },
  {
    "path": "lua/gacha/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.StaggeredGridLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"java.util.Calendar\"\n\nlocal calender = Calendar.getInstance()\n\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\nlocal max\nlocal data = {}\nlocal adapter\nlocal imageWidth = uihelper.getScreenWidth() / 2\n\n-- create view table\nlocal layout = {\n    RecyclerView,\n    id = \"recyclerView\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"200dp\",\n        scaleType = \"fitXY\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_gravity = \"right\",\n        background = \"#88000000\",\n        paddingLeft = \"6dp\",\n        paddingRight = \"6dp\",\n        paddingTop = \"2dp\",\n        paddingBottom = \"2dp\",\n        textSize = \"10sp\",\n        visibility = 8,\n        textColor = \"#aaffffff\",\n    },\n    {\n        View,\n        id = \"layer\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        background = \"@drawable/layout_selector_tran\",\n        clickable = true,\n    },\n}\n\nlocal function fetchData()\n\n    local year = calender.get(Calendar.YEAR)\n    local month = calender.get(Calendar.MONTH) + 1\n    local day = calender.get(Calendar.DAY_OF_MONTH)\n\n    local markFrom = string.format('%04d-%02d-%02d', year, month, day)\n    calender.add(Calendar.DAY_OF_MONTH, -1)\n    year = calender.get(Calendar.YEAR)\n    month = calender.get(Calendar.MONTH) + 1\n    day = calender.get(Calendar.DAY_OF_MONTH)\n    local mark = string.format('%04d-%02d-%02d', year, month, day)\n\n    local url = string.format(\"http://gacha.163.com/api/v1/ranking/pic?type=0&mark=%s&fromMark=%s\", mark, markFrom)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local json = JSON.decode(body)\n        local html = json.result.rankingHtml\n        uihelper.runOnUiThread(activity, function()\n            local s = #data\n            for w, h, url in string.gmatch(html, 'data[-]width=\"([0-9]+)\" data[-]height=\"([0-9]+)\".-data[-]src=\"(.-)\"') do\n                local item = { url = url, w = w, h = h }\n                local id, type = string.match(item.url, 'http://gacha[.]nosdn[.]127[.]net/([0-9a-z]+)[.]([a-z]+)')\n                item.id = id\n                item.type = type\n                item.fullUrl = string.format('http://gacha.nosdn.127.net/%s.%s', id, type)\n                item.calcHeight = math.floor(imageWidth * tonumber(item.h) / tonumber(item.w))\n                data[#data + 1] = item\n            end\n            adapter.notifyItemRangeChanged(s, #data)\n        end)\n    end)\nend\n\nlocal function launchDetail(item)\n    local args = { uris = { item.fullUrl } }\n    PicturePreviewActivity.start(activity, JSON.encode(args))\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.getLayoutParams().width = imageWidth\n            holder.itemView.setTag(views)\n            views.layer.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1\n                launchDetail(data[position])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            views.iv_image.getLayoutParams().height = item.calcHeight\n            LuaImageLoader.load(views.iv_image, item.url)\n            if position == #data then fetchData() end\n        end,\n    }))\n    recyclerView.setLayoutManager(StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL))\n    recyclerView.setAdapter(adapter)\n    fetchData()\nend\n"
  },
  {
    "path": "lua/gamesky/info.json",
    "content": "{\n  \"id\": \"pub.hanks.gamesky\",\n  \"name\": \"游民星空\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088ce8e81426a?w=150&h=150&f=png&s=3228\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.0\",\n  \"versionCode\": 2,\n  \"desc\": \"大量游戏截图，高清\"\n}\n"
  },
  {
    "path": "lua/gamesky/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.StaggeredGridLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\n\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\nlocal data = {}\nlocal adapter\nlocal imageWidth = uihelper.getScreenWidth()\nlocal list = { index = 1, page = 1, urls = {} }\nlocal maxHeight = uihelper.dp2px(640)\n\nmath.randomseed(os.time())\n--- -然后不断产生随机数\nlist.page = math.floor(math.random() * 160)\n-- create view table\nlocal layout = {\n    RelativeLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        RecyclerView,\n        id = \"recyclerView\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n    {\n        TextView,\n        id = \"tv_loading\",\n        text = \"加载中....\",\n        textSize = \"12sp\",\n        textColor = \"#888888\",\n        layout_margin = \"16dp\",\n        layout_alignParentBottom = true,\n        layout_alignParentRight = true,\n    }\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"200dp\",\n        scaleType = \"fitXY\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_gravity = \"right\",\n        background = \"#88000000\",\n        paddingLeft = \"6dp\",\n        paddingRight = \"6dp\",\n        paddingTop = \"2dp\",\n        paddingBottom = \"2dp\",\n        textSize = \"10sp\",\n        visibility = 8,\n        textColor = \"#aaffffff\",\n    },\n    {\n        View,\n        id = \"layer\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        background = \"@drawable/layout_selector_tran\",\n        clickable = true,\n    },\n}\n\nlocal function fetchData()\n    tv_loading.setVisibility(0)\n    local url = string.format('http://pic.gamersky.com/home/getimagesindex?sort=hot_desc&pageIndex=%d&pageSize=50&nodeId=21086', list.page)\n\n    LuaHttp.request({ url = url }, function(error, code, body)\n        list.page = list.page + 1\n        body = body:gsub('\\\\\"', '\"')\n        body = body:sub(2, #body - 1)\n        local arr = JSON.decode(body).body\n        uihelper.runOnUiThread(activity, function()\n            local s = #data\n            for i = 1, #arr do\n                local fullUrl = arr[i].originImg\n                local w, h = arr[i].width, arr[i].height\n                local item = { url = fullUrl, w = w, h = h }\n                item.calcHeight = math.floor(imageWidth * tonumber(item.h) / tonumber(item.w))\n                if item.calcHeight > maxHeight then item.calcHeight = maxHeight end\n                data[#data + 1] = item\n            end\n            tv_loading.setVisibility(8)\n            adapter.notifyItemRangeChanged(s, #data)\n        end)\n    end)\nend\n\nlocal function launchDetail(item)\n    local args = { uris = { item.url }, headers = { 'Referer:http://gamersky.com', 'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36' } }\n    PicturePreviewActivity.start(activity, JSON.encode(args))\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.getLayoutParams().width = imageWidth\n            holder.itemView.setTag(views)\n            views.layer.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1\n                launchDetail(data[position])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            views.iv_image.getLayoutParams().height = item.calcHeight\n            LuaImageLoader.load(views.iv_image, item.url)\n            if position == #data then fetchData() end\n        end,\n    }))\n    recyclerView.setLayoutManager(StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL))\n    recyclerView.setAdapter(adapter)\n    fetchData()\nend\n"
  },
  {
    "path": "lua/graphmovies/detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- 图解电影\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nimport \"android.os.Build\"\nimport \"android.view.View\"\n\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#ff000000\",\n    {\n        LinearLayout,\n        orientation = \"horizontal\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#ff000000\",\n        gravity = \"center_vertical\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginLeft = \"8dp\",\n            scaleType = \"centerInside\",\n            src = \"@drawable/ic_menu_back\",\n        },\n        {\n            TextView,\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            singleLine = true,\n            textIsSelectable = true,\n            ellipsize = \"end\",\n            id = \"tv_title\",\n            gravity = \"center_vertical\",\n            paddingLeft = \"8dp\",\n            textColor = \"#ffffff\",\n            textSize = \"16sp\",\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ListView,\n            id = \"listview\",\n            dividerHeight = 0,\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal item_view = {\n    LinearLayout,\n    layout_width = \"fill\",\n    orientation = \"vertical\",\n    paddingLeft = \"16dp\",\n    paddingRight = \"16dp\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"220dp\",\n    },\n    {\n        TextView,\n        id = \"tv_content\",\n        layout_width = \"fill\",\n        lineSpacingMultiplier = '1.3',\n        paddingTop = \"8dp\",\n        paddingBottom = \"8dp\",\n        textSize = \"14sp\",\n        textColor = \"#444444\",\n    },\n}\n\nlocal data = {}\nlocal baseUrl = \"\"\nlocal adapter\n\nlocal function unicode_to_utf8(convertStr)\n    local t = {}\n    for a in string.gmatch(convertStr, '\\\\u([0-9a-z][0-9a-z][0-9a-z][0-9a-z])') do\n        if #a == 4 then\n            local n = tonumber(a, 16)\n            assert(n, \"String decoding failed: bad Unicode escape \" .. a)\n            local x\n            if n < 0x80 then\n                x = string.char(n % 0x80)\n            elseif n < 0x800 then\n                -- [110x xxxx] [10xx xxxx]\n                x = string.char(0xC0 + (math.floor(n / 64) % 0x20), 0x80 + (n % 0x40))\n            else\n                -- [1110 xxxx] [10xx xxxx] [10xx xxxx]\n                x = string.char(0xE0 + (math.floor(n / 4096) % 0x10), 0x80 + (math.floor(n / 64) % 0x40), 0x80 + (n % 0x40))\n            end\n            convertStr = string.gsub(convertStr, '\\\\u' .. a, x)\n        end\n    end\n    return convertStr\nend\n\nlocal function getData()\n    local jsonStr = activity.getIntent().getStringExtra('json')\n    local json = JSON.decode(jsonStr)\n    listview.setVisibility(0)\n    progressBar.setVisibility(8)\n    local url1 = string.format('http://h5.graphmovie.com/gmspanel/olr/rw.shu.php?m=%s&p=web&c=me&v=0&n=%s', json.orkey, json.name)\n    tv_title.setText(url1)\n    LuaHttp.request({ url = url1 }, function(error, code, body)\n        -- get orkey\n        local orkey = string.match(body, \"script.php[?]orkey=(.-)'\")\n        local options = {\n            url = string.format('http://h5.graphmovie.com/gmspanel/olr/script.php?orkey=%s', orkey),\n            method = 'POST',\n            headers = {\n                \"X-Requested-With: XMLHttpRequest\",\n                \"Content-Type: application/x-www-form-urlencoded\",\n            },\n            formData = {\n                \"a:1\",\n            },\n        }\n        LuaHttp.request(options, function(e, c, b)\n            baseUrl = string.match(b, 'data\":{\"p\":\"(.-)\"')\n            print(baseUrl)\n            for m, r in string.gmatch(b, '\"m\":\"(.-)\",\"r\":\"(.-)\"') do\n                data[#data + 1] = { m = m, r = r }\n            end\n            uihelper.runOnUiThread(activity, function()\n                adapter.notifyDataSetChanged()\n            end)\n        end)\n    end)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    back.onClick = function()\n        activity.finish()\n    end\n\n    adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n        getCount = function() return #data end,\n        getView = function(position, convertView, parent)\n            position = position + 1 -- lua 索引从 1开始\n            if position == #data then\n                getData()\n            end\n            if convertView == nil then\n                local views = {} -- store views\n                convertView = loadlayout(item_view, views, ListView)\n                convertView.getLayoutParams().width = parent.getWidth()\n                convertView.setTag(views)\n            end\n            local views = convertView.getTag()\n            local item = data[position]\n            if item then\n                local img = item.m\n                if not img:find('^http') then\n                    img = baseUrl .. img\n                end\n                img = img:gsub('\\\\/', '/')\n                LuaImageLoader.load(views.iv_image, img)\n                views.tv_content.setText(unicode_to_utf8(item.r or ''))\n            end\n            return convertView\n        end\n    }))\n    listview.setAdapter(adapter)\n\n    getData()\nend\n"
  },
  {
    "path": "lua/graphmovies/info.json",
    "content": "{\n  \"id\": \"pub.hanks.graphmovies\",\n  \"name\": \"图解电影\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088d46dc93a57?w=150&h=150&f=png&s=6212\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 3,\n  \"desc\": \"图片+文字看电影，graphmovie.com\"\n}\n"
  },
  {
    "path": "lua/graphmovies/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport(\"androlua.LuaImageLoader\")\n\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    background = \"#f1f1f1\",\n    statusBarColor = \"#F0000000\",\n    {\n        TextView,\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#F0000000\",\n        gravity = \"center\",\n        text = \"图解电影\",\n        textColor = \"#FFFFFF\",\n        textSize = \"18sp\",\n    },\n    {\n        ListView,\n        id = \"listview\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"16dp\",\n        scrollBarStyle = \"outsideOverlay\",\n        dividerHeight = 0,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n}\n\nlocal item_view = {\n    LinearLayout,\n    layout_width = \"fill\",\n    orientation = \"vertical\",\n    background = \"#FFFFFF\",\n    {\n        View,\n        layout_width = \"fill\",\n        layout_height = \"12dp\",\n        background = \"#f1f1f1\",\n    },\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"200dp\",\n        scaleType = \"centerCrop\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_width = \"fill\",\n        paddingTop = \"16dp\",\n        paddingBottom = \"16dp\",\n        paddingLeft = \"12dp\",\n        paddingRight = \"12dp\",\n        maxLines = \"2\",\n        lineSpacingMultiplier = '1.2',\n        textSize = \"16sp\",\n        textColor = \"#222222\",\n    },\n    {\n        TextView,\n        id = \"tv_subtitle\",\n        layout_width = \"fill\",\n        paddingLeft = \"12dp\",\n        paddingRight = \"12dp\",\n        paddingBottom = \"16dp\",\n        lineSpacingMultiplier = '1.2',\n        textSize = \"14sp\",\n        textColor = \"#888888\",\n    },\n    -- {\n    --     View,\n    --     layout_width = \"fill\",\n    --     layout_height = 2,\n    --     background = \"#eeeeee\",\n    -- },\n    -- {\n    --   LinearLayout,\n    --   orientation = \"horizontal\",\n    --   layout_width = \"fill\",\n    --   layout_height = \"48dp\",\n    --   gravity = \"center_vertical\",\n    --   {\n    --     TextView,\n    --     layout_weight = 1,\n    --     id = \"tv_username\",\n    --     textSize = \"12sp\",\n    --     textColor = \"#888888\",\n    --   },\n    --   {\n    --     TextView,\n    --     id = \"tv_views\",\n    --     textSize = \"12sp\",\n    --     textColor = \"#888888\",\n    --   },\n    --   {\n    --     TextView,\n    --     id = \"tv_rate\",\n    --     textSize = \"12sp\",\n    --     textColor = \"#888888\",\n    --   },\n    -- },\n}\n\n\nlocal data = {\n    dailyList = {},\n}\nlocal adapter\nlocal orkey\n\nlocal function getJsonData()\n    local url = string.format('http://www.graphmovies.com/home/2/get.php?orkey=%s', orkey)\n    local options = {\n        url = url,\n        method = 'POST',\n        headers = {\n            \"X-Requested-With: XMLHttpRequest\",\n            \"Content-Type: application/x-www-form-urlencoded\",\n        },\n        formData = {\n            \"p:15\",\n            \"type:movie\",\n            \"zone:0\",\n            \"tag:0\",\n            \"showtime:0\",\n            \"level:0\",\n        },\n    }\n    if #data.dailyList > 0 then\n        options.formData[#options.formData + 1] = 't:' .. (data.dailyList[#data.dailyList].onlinetime or '')\n    end\n    LuaHttp.request(options, function(e, code, body)\n        local json = JSON.decode(body)\n        local arr = json.data\n        uihelper.runOnUiThread(activity, function()\n            for i = 1, #arr do\n                data.dailyList[#data.dailyList + 1] = arr[i]\n            end\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nlocal function getData()\n    if orkey == nil then\n        LuaHttp.request({ url = 'http://www.graphmovies.com/home/2/' }, function(error, code, body)\n            orkey = string.match(body, \"get.php[?]orkey=(.-)'\")\n            getJsonData()\n        end)\n    else\n        getJsonData()\n    end\nend\n\nlocal log = require('log')\nfunction launchDetail(item)\n    local json = { orkey = item.orkey, name = item.name }\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'graphmovies/detail.lua')\n    intent.putExtra(\"json\", JSON.encode(json))\n    activity.startActivity(intent)\nend\n\nfunction onDestroy()\n    LuaHttp.cancelAll()\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x00000000)\n    activity.setContentView(loadlayout(layout))\n    adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n        getCount = function() return #data.dailyList end,\n        getView = function(position, convertView, parent)\n            position = position + 1 -- lua 索引从 1开始\n            if position == #data.dailyList then\n                getData()\n            end\n            if convertView == nil then\n                local views = {} -- store views\n                convertView = loadlayout(item_view, views, ListView)\n                convertView.getLayoutParams().width = parent.getWidth()\n                convertView.setTag(views)\n            end\n            local views = convertView.getTag()\n            local item = data.dailyList[position]\n            if item then\n                LuaImageLoader.load(views.iv_image, item.bpic or '')\n                views.tv_title.setText(item.name or 'error title')\n                views.tv_subtitle.setText(item.subtitle or '')\n                -- views.tv_username.setText(item.users[1].name)\n                -- views.tv_views.setText(item.readdata.played)\n                -- views.tv_rate.setText(item.score .. '分')\n            end\n            return convertView\n        end\n    }))\n    listview.setAdapter(adapter)\n    listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n        onItemClick = function(adapter, view, position, id)\n            launchDetail(data.dailyList[position + 1])\n        end,\n    }))\n    getData()\nend\n"
  },
  {
    "path": "lua/huaban-popular/info.json",
    "content": "{\n  \"id\": \"pub.hanks.huaban-popular\",\n  \"name\": \"花瓣热门\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088d9ccb657bf?w=150&h=150&f=png&s=2265\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.4\",\n  \"versionCode\": 5,\n  \"desc\": \"花瓣网热门图片采集\"\n}\n"
  },
  {
    "path": "lua/huaban-popular/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.StaggeredGridLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"android.graphics.drawable.ColorDrawable\"\n\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\nlocal date = os.date(\"%Y%m%d\", os.time() - 60 * 60 * 24) -- 20170518\nlocal max\nlocal data = {}\nlocal adapter\nlocal imageWidth = uihelper.getScreenWidth() / 2\nlocal colors = {0xffF9F8EB, 0xffABCDCB, 0xffECECEC, 0xffF5F5F5, 0xffF5FEFF, 0xffE8F1F5, 0xffCDE3EB, 0xffFFEBEB}\n-- create view table\nlocal layout = {\n    RecyclerView,\n    id = \"recyclerView\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"200dp\",\n        scaleType = \"fitXY\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_gravity = \"right\",\n        background = \"#88000000\",\n        paddingLeft = \"6dp\",\n        paddingRight = \"6dp\",\n        paddingTop = \"2dp\",\n        paddingBottom = \"2dp\",\n        textSize = \"10sp\",\n        visibility = 8,\n        textColor = \"#aaffffff\",\n    },\n    {\n        View,\n        id = \"layer\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        background = \"@drawable/layout_selector_tran\",\n        clickable = true,\n    },\n}\n\nlocal function fetchData()\n\n    local url = 'http://huaban.com/popular/?limit=20&wfl=1'\n    if max then\n        url = string.format('http://huaban.com/popular/?max=%d&limit=20&wfl=1', max)\n    end\n    local options = {\n        url = url,\n        headers = {\n            \"X-Requested-With:XMLHttpRequest\",\n        }\n    }\n    LuaHttp.request(options, function(error, code, body)\n        local json = JSON.decode(body)\n        local arr = json.pins\n        max = arr[#arr].pin_id\n        uihelper.runOnUiThread(activity, function()\n            local s = #data\n            for i = 1, #arr do\n                local item = arr[i]\n                item.url = string.format('http://img.hb.aicdn.com/%s', item.file.key)\n                item.calcHeight = math.floor(imageWidth * tonumber(item.file.height) / tonumber(item.file.width))\n                data[#data + 1] = item\n            end\n            adapter.notifyItemRangeChanged(s, #arr)\n        end)\n    end)\nend\n\nlocal function launchDetail(item,index)\n    local args = { uris = {}, currentIndex=index }\n    for i=1,#data do\n        args.uris[i] = data[i].url\n    end\n    PicturePreviewActivity.start(activity, JSON.encode(args))\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.getLayoutParams().width = imageWidth\n            holder.itemView.setTag(views)\n            views.layer.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1\n                launchDetail(data[position],position-1)\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            local colorIndex = position % 8\n\n            position = position + 1\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            views.iv_image.getLayoutParams().height = item.calcHeight\n            -- LuaImageLoader.load(views.iv_image, item.url)\n            LuaImageLoader.load(views.iv_image.getContext(), views.iv_image, item.url, 0, 0,\n                            ColorDrawable(colors[colorIndex + 1]), ColorDrawable(colors[colorIndex + 1]))\n\n            if position == #data then fetchData() end\n        end,\n    }))\n    recyclerView.setLayoutManager(StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL))\n    recyclerView.setAdapter(adapter)\n    fetchData()\nend\n"
  },
  {
    "path": "lua/iciba/info.json",
    "content": "{\n  \"id\": \"pub.hanks.iciba\",\n  \"name\": \"金山词霸\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088df179ab4d7?w=150&h=150&f=png&s=2753\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.2\",\n  \"versionCode\": 4,\n  \"desc\": \"金山词霸，用来查单词\"\n}\n"
  },
  {
    "path": "lua/iciba/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.view.inputmethod.InputMethodManager\"\nimport \"android.support.v4.widget.Space\"\n\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\nlocal log = require('log')\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    {\n        LinearLayout,\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        orientation = \"horizontal\",\n        layout_marginTop = \"48dp\",\n        layout_marginLeft = \"16dp\",\n        layout_marginRight = \"16dp\",\n        background = \"#FFFFFF\",\n        elevation = \"2dp\",\n        {\n            EditText,\n            layout_height = \"fill\",\n            layout_weight = 1,\n            paddingLeft = \"12sp\",\n            gravity = \"center_vertical\",\n            id = \"et_keyword\",\n            singleLine = true,\n            textSize = \"14sp\",\n            textColor = \"#888888\",\n            background = \"#00FFFFFF\",\n        },\n        {\n            Button,\n            background = '#0090ff',\n            id = \"tv_search\",\n            textColor = '#ffffff',\n            layout_width = \"48dp\",\n            layout_height = \"48dp\",\n            text = \"G\",\n        },\n    },\n    {\n        ScrollView,\n        layout_width = \"fill\",\n        padding = \"16dp\",\n        clipToPadding = false,\n        {\n            LinearLayout,\n            id = \"layout_content\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n            orientation = \"vertical\",\n        }\n    }\n}\n\nlocal adapter\n\nlocal function unicode_to_utf8(convertStr)\n    for a in string.gmatch(convertStr, '\\\\u([0-9a-z][0-9a-z][0-9a-z][0-9a-z])') do\n        if #a == 4 then\n            local n = tonumber(a, 16)\n            assert(n, \"String decoding failed: bad Unicode escape \" .. a)\n            local x\n            if n < 0x80 then\n                x = string.char(n % 0x80)\n            elseif n < 0x800 then\n                x = string.char(0xC0 + (math.floor(n / 64) % 0x20), 0x80 + (n % 0x40))\n            else\n                x = string.char(0xE0 + (math.floor(n / 4096) % 0x10), 0x80 + (math.floor(n / 64) % 0x40), 0x80 + (n % 0x40))\n            end\n            convertStr = string.gsub(convertStr, '\\\\u' .. a, x)\n        end\n    end\n    return convertStr\nend\n\nlocal function text(txt, size, color)\n    return {\n        TextView,\n        background = \"@drawable/layout_selector_tran\",\n        layout_width = \"fill\",\n        paddingTop = \"24dp\",\n        textIsSelectable = true,\n        gravity = \"center_vertical\",\n        text = txt,\n        textSize = size,\n        textColor = color,\n    }\nend\n\nlocal function text_lr(textLeft, textRight)\n    return {\n        LinearLayout,\n        layout_width = \"fill\",\n        paddingTop = \"8dp\",\n        orientation = \"horizontal\",\n        {\n            TextView,\n            layout_width = \"30dp\",\n            text = textLeft,\n            textIsSelectable = true,\n            textSize = '15sp',\n            textColor = '#888888',\n        },\n        {\n            TextView,\n            layout_width = \"fill\",\n            textIsSelectable = true,\n            lineSpacingMultiplier = 1.3,\n            text = textRight,\n            textSize = '14sp',\n            textColor = '#222222',\n        },\n    }\nend\n\nlocal function text_tb(textTop, textBottom)\n    return {\n        LinearLayout,\n        layout_width = \"fill\",\n        paddingTop = \"8dp\",\n        orientation = \"vertical\",\n        {\n            TextView,\n            layout_width = \"fill\",\n            text = textTop,\n            textSize = '13sp',\n            lineSpacingMultiplier = 1.3,\n            textIsSelectable = true,\n            textColor = '#222222',\n        },\n        {\n            TextView,\n            layout_width = \"fill\",\n            layout_marginTop = \"8dp\",\n            text = textBottom,\n            textSize = '12sp',\n            textColor = '#888888',\n            textIsSelectable = true,\n            lineSpacingMultiplier = 1.3,\n        },\n    }\nend\n\nlocal function fillData(json)\n    layout_content.removeAllViews()\n    local symbol = json.basic\n    if symbol then\n        layout_content.addView(loadlayout(text('基本释义', '16sp', '#0090ff')))\n\n        local ph = {}\n        if symbol['uk-phonetic'] then ph[#ph + 1] = '英[' .. symbol['uk-phonetic'] .. ']' end\n        if symbol['us-phonetic'] then ph[#ph + 1] = '美[' .. symbol['us-phonetic'] .. ']' end\n        layout_content.addView(loadlayout(text(table.concat(ph, '  '), '14sp', '#222222')))\n\n        if symbol.explains and #symbol.explains > 0 then\n            for i = 1, #symbol.explains do\n                print(symbol.explains[i])\n                layout_content.addView(loadlayout(text(symbol.explains[i], '16sp', '#333333'), {}, LinearLayout))\n            end\n        end\n    end\n\nend\n\nlocal function search(keyword)\n    local url = string.format('http://fanyi.youdao.com/openapi.do?keyfrom=LinYaoTian&key=141887672&type=data&doctype=json&version=1.2&q=%s', keyword)\n    print(url)\n    local options = { url = url }\n    LuaHttp.request(options, function(e, code, body)\n        uihelper.runOnUiThread(activity, function()\n            local json = JSON.decode(body)\n            fillData(json)\n        end)\n    end)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    tv_search.onClick = function(view)\n        local imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE)\n        imm.hideSoftInputFromWindow(tv_search.getWindowToken(), 0)\n        local keyword = et_keyword.getText().toString()\n        search(keyword)\n    end\nend\n"
  },
  {
    "path": "lua/it168/activity_news_detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nlocal uihelper = require \"uihelper\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#3164ba\",\n    {\n        LinearLayout,\n        orientation = \"horizontal\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#3164ba\",\n        gravity = \"center_vertical\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginLeft = \"8dp\",\n            scaleType = \"centerInside\",\n            src = \"@drawable/ic_menu_back\",\n        },\n        {\n            TextView,\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            singleLine = true,\n            textIsSelectable = true,\n            ellipsize = \"end\",\n            id = \"tv_title\",\n            gravity = \"center_vertical\",\n            paddingLeft = \"8dp\",\n            textColor = \"#ffffff\",\n            textSize = \"16sp\",\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            LuaWebView,\n            id = \"webview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        },\n        {\n            FrameLayout,\n            layout_gravity = 85,\n            layout_width = \"100dp\",\n            layout_height = \"100dp\",\n            id = \"layout_content\",\n        }\n    }\n}\n\nlocal css = [[\n    video{width:100%}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-webkit-text-size-adjust:100%}body{font-family:'Helvetica Neue',Helvetica,Arial,Sans-serif;background:#fff;padding-top:0;margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0}h1,h2,h3,h4,h5,h6{font-size:16px}abbr[title]{border-bottom:1px dotted}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:\\201C\\201D\\2018\\2019}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0;vertical-align:middle;color:transparent;font-size:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}table{border-collapse:collapse;border-spacing:0;overflow:hidden}a{text-decoration:none}blockquote{border-left:3px solid #d0e5f2;font-style:normal;display:block;vertical-align:baseline;font-size:100%;margin:.5em 0;padding:0 0 0 1em}ul,ol{padding-left:20px}.content{color:#444;line-height:1.6em;font-size:16px;margin:16px}.content img{max-width:100%;display:block;margin:30px auto}.content img+img{margin-top:15px}.content img[src*=\"zhihu.com/equation\"]{display:inline-block;margin:0 3px}.content a{color:#259}.content a:hover{text-decoration:underline}\n]]\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html>\n<head>\n\t<title></title>\n\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n\t<meta name=\"viewport\" content=\"width=device-width; initial-scale=1; minimum-scale=1; maximum-scale=2\">\n\t<meta content=\"width=device-width,user-scalable=no\" name=\"viewport\">\n\t<style type=\"text/css\">\t%s </style>\n</head>\n<body>\n<div class=\"content\"> %s </div>\n<script type=\"text/javascript\">\nfunction openImgActivity(a,b){var c=JSON.stringify({currentIndex:b,uris:a});var d=\"hydrogen://pub.hydrogen.android?action=open_img&data=\"+c;var e=document.createElement(\"iframe\");e.src=d;e.style.display=\"none\";document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},2000)}function init(){var a=document.querySelectorAll(\".content img\");for(var b=0;b<a.length;b++){a[b].addEventListener(\"click\",function(g){var e=g.target||g.srcElement;var c=[];var d=0;var h=document.querySelectorAll(\".content img\");for(var f=0;f<h.length;f++){c[f]=h[f].getAttribute(\"src\");if(e.getAttribute(\"src\").indexOf(c[f])!=-1){d=f}}openImgActivity(c,d)})}}init();\n</script>\n</body>\n</html>\n]]\n\nlocal function html_unescape(s)\n    return s:gsub(\"&lt;\", \"<\"):gsub(\"&gt;\", \">\"):gsub(\"&amp;\", \"&\"):gsub(\"&quot;\", '\"'):gsub(\"&#39;\", \"'\"):gsub(\"&#47;\", \"/\")\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0xffd22222)\n    activity.setContentView(loadlayout(layout))\n    back.onClick = function()\n        activity.finish()\n    end\n    local url = activity.getIntent().getStringExtra('url')\n    tv_title.setText(url or \"error url\")\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    print(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local content = string.match(body, '<div class=\"IT168Detail\">(.-)</div>%s+<div%s+class=\"open.more.box\"')\n        print(content)\n        local data = string.format(htmlTemplate, css, html_unescape(content))\n        uihelper.runOnUiThread(activity, function()\n            webview.loadData(data, \"text/html; charset=UTF-8\", nil)\n        end)\n    end)\nend\n\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend\n"
  },
  {
    "path": "lua/it168/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.os.Build\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require(\"log\")\nlocal function getData(params, data, adapter, fragment, swipe_layout, reload)\n    if reload then\n        params.page = 1\n    end\n    local url = string.format('http://api.cms.it168.com/api/it168/datas/list?jsoncallback=angular.callbacks._1&id=%d&page=%d&type=%d', params.rid, params.page, params.type)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then return end\n        local txt\n        if body then\n            txt = string.sub(body, 22, string.len(body)-1)\n        end\n        local json = JSON.decode(txt)\n        params.page = params.page + 1\n        local arr = json.data\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                for k, _ in ipairs(data) do data[k] = nil end\n            end\n            local s = #data\n            for i = 1, #arr do\n                data[#data + 1] = arr[i]\n            end\n            adapter.notifyDataSetChanged()\n            swipe_layout.setRefreshing(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, item)\n    log.print_r(item)\n    local activity = fragment.getActivity()\n    if item == nil or item.link == nil then\n        activity.toast('没有 url 可以打开')\n        return\n    end\n    local url = string.format('http://m.it168.com/detailText.html?id=%d', item.id)\n    local activity = fragment.getActivity()\n    WebViewActivity.start(activity, url, 0xff3164ba)\n\n    -- local intent = Intent(activity, LuaActivity)\n    -- intent.putExtra(\"luaPath\", 'it168/activity_news_detail.lua')\n    -- intent.putExtra(\"url\", )\n    -- activity.startActivity(intent)\nend\n\nlocal function newInstance(rid, type)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            ListView,\n            id = \"listview\",\n            background = '#FFFFFF',\n            dividerHeight = 0,\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"114dp\",\n        paddingLeft = \"8dp\",\n        paddingRight = \"8dp\",\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_marginTop=\"16dp\",\n            layout_gravity = \"right\",\n            layout_width = \"110dp\",\n            layout_height = \"82dp\",\n            scaleType = \"centerCrop\",\n        },\n        {\n            TextView,\n            layout_marginTop=\"16dp\",\n            id = \"tv_title\",\n            layout_width = \"fill\",\n            layout_marginRight = \"130dp\",\n            maxLines = 2,\n            lineSpacingMultiplier = 1.3,\n            textSize = \"16sp\",\n            textColor = \"#333333\",\n        },\n        {\n            TextView,\n            layout_gravity = \"bottom\",\n            id = \"tv_desc\",\n            layout_width = \"fill\",\n            layout_marginRight = '16dp',\n            layout_marginBottom = '16dp',\n            maxLines = 4,\n            lineSpacingMultiplier = 1.3,\n            textSize = \"12sp\",\n            textColor = \"#666666\",\n        },\n        {View, layout_width = \"fill\", layout_height = \"1dp\", background=\"#f1f1f1\",},\n    }\n\n\n    local hadLoadData\n    local isVisible\n    local lastId\n    local params = { rid = rid, page = 1, type = type }\n    local data = {}\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(params, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        convertView.getLayoutParams().width = parent.getWidth()\n                        convertView.setTag(views)\n                        views.tv_title.setTypeface(nil, 1);\n                    end\n                    local views = convertView.getTag()\n                    local item = data[position]\n                    if item then\n                        if item.imgSrc then\n                            views.iv_image.setVisibility(0)\n                            local imgUrl = item.imgSrc\n                            if item.class == \"item-img\" then\n                                imgUrl = item.imgSrc.src[1].imgSrc\n                            end\n                            pcall(function() \n                                LuaImageLoader.load(views.iv_image, imgUrl or \"\")\n                            end)\n                        else\n                            views.iv_image.setVisibility(8)\n                        end\n                        views.tv_title.setText(item.text or 'ERROR TITLE')\n                        views.tv_desc.setText(os.date(\"%m月%d日\", item.time/1000))\n                    end\n                    if position == #data then getData(params, data, adapter, fragment, ids.swipe_layout) end\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    launchDetail(fragment, data[position + 1])\n                end,\n            }))\n            ids.swipe_layout.setRefreshing(true)\n            ids.swipe_layout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    getData(params, data, adapter, fragment, ids.swipe_layout, true)\n                end\n            }))\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/it168/info.json",
    "content": "{\n  \"id\": \"pub.hanks.it168\",\n  \"name\": \"手机评测\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088e4cf781c7a?w=150&h=150&f=png&s=6297\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 3,\n  \"desc\": \"IT168.com 手机评测\"\n}\n"
  },
  {
    "path": "lua/it168/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\n\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\n\nlocal fragmentNews = require \"it168/fragment_news\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#3164ba\",\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#3164ba\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\n\ntable.insert(data.fragments, fragmentNews.newInstance(1,2))\ntable.insert(data.titles, '评测')\n\ntable.insert(data.fragments, fragmentNews.newInstance(1,0))\ntable.insert(data.titles, '手机')\n\ntable.insert(data.fragments, fragmentNews.newInstance(8,0))\ntable.insert(data.titles, '笔记本')\ntable.insert(data.titles, '手机')\n\ntable.insert(data.fragments, fragmentNews.newInstance(4,0))\ntable.insert(data.titles, '键盘鼠标')\n\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0xff3164ba)\n    activity.setContentView(loadlayout(layout))\n    viewPager.setAdapter(adapter)\n    tab.setSelectedTabIndicatorColor(0xffffffff)\n    tab.setTabTextColors(0x88ffffff, 0xffffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n"
  },
  {
    "path": "lua/ithome/activity_news_detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nlocal uihelper = require \"uihelper\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#D22222\",\n    {\n        LinearLayout,\n        orientation = \"horizontal\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#D22222\",\n        gravity = \"center_vertical\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginLeft = \"8dp\",\n            scaleType = \"centerInside\",\n            src = \"@drawable/ic_menu_back\",\n        },\n        {\n            TextView,\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            singleLine = true,\n            textIsSelectable = true,\n            ellipsize = \"end\",\n            id = \"tv_title\",\n            gravity = \"center_vertical\",\n            paddingLeft = \"8dp\",\n            textColor = \"#ffffff\",\n            textSize = \"16sp\",\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            LuaWebView,\n            id = \"webview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        },\n        {\n            FrameLayout,\n            layout_gravity = 85,\n            layout_width = \"100dp\",\n            layout_height = \"100dp\",\n            id = \"layout_content\",\n        }\n    }\n}\n\nlocal css = [[\n    video{width:100%}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-webkit-text-size-adjust:100%}body{font-family:'Helvetica Neue',Helvetica,Arial,Sans-serif;background:#fff;padding-top:0;margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0}h1,h2,h3,h4,h5,h6{font-size:16px}abbr[title]{border-bottom:1px dotted}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:\\201C\\201D\\2018\\2019}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0;vertical-align:middle;color:transparent;font-size:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}table{border-collapse:collapse;border-spacing:0;overflow:hidden}a{text-decoration:none}blockquote{border-left:3px solid #d0e5f2;font-style:normal;display:block;vertical-align:baseline;font-size:100%;margin:.5em 0;padding:0 0 0 1em}ul,ol{padding-left:20px}.content{color:#444;line-height:1.6em;font-size:16px;margin:16px}.content img{max-width:100%;display:block;margin:30px auto}.content img+img{margin-top:15px}.content img[src*=\"zhihu.com/equation\"]{display:inline-block;margin:0 3px}.content a{color:#259}.content a:hover{text-decoration:underline}\n]]\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html>\n<head>\n\t<title></title>\n\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n\t<meta name=\"viewport\" content=\"width=device-width; initial-scale=1; minimum-scale=1; maximum-scale=2\">\n\t<meta content=\"width=device-width,user-scalable=no\" name=\"viewport\">\n\t<style type=\"text/css\">\t%s </style>\n</head>\n<body>\n<div class=\"content\"> %s </div>\n<script type=\"text/javascript\">\nfunction openImgActivity(a,b){var c=JSON.stringify({currentIndex:b,uris:a});var d=\"hydrogen://pub.hydrogen.android?action=open_img&data=\"+c;var e=document.createElement(\"iframe\");e.src=d;e.style.display=\"none\";document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},2000)}function init(){var a=document.querySelectorAll(\".content img\");for(var b=0;b<a.length;b++){a[b].addEventListener(\"click\",function(g){var e=g.target||g.srcElement;var c=[];var d=0;var h=document.querySelectorAll(\".content img\");for(var f=0;f<h.length;f++){c[f]=h[f].getAttribute(\"src\");if(e.getAttribute(\"src\").indexOf(c[f])!=-1){d=f}}openImgActivity(c,d)})}}init();\n</script>\n</body>\n</html>\n]]\n\nlocal function html_unescape(s)\n    return s:gsub(\"&lt;\", \"<\"):gsub(\"&gt;\", \">\"):gsub(\"&amp;\", \"&\"):gsub(\"&quot;\", '\"'):gsub(\"&#39;\", \"'\"):gsub(\"&#47;\", \"/\")\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0xffd22222)\n    activity.setContentView(loadlayout(layout))\n    back.onClick = function()\n        activity.finish()\n    end\n    local newsid = activity.getIntent().getStringExtra('newsid')\n    local originalUrl = string.format('http://wap.ithome.com/html/%s.htm', newsid)\n    tv_title.setText(originalUrl)\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    local url = string.format(\"http://api.ithome.com/xml/newscontent/%s/%s.xml\", newsid:sub(1, 3), newsid:sub(4, 6))\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local content = string.match(body, '<detail.->(.-)</detail>')\n        local data = string.format(htmlTemplate, css, html_unescape(content))\n        uihelper.runOnUiThread(activity, function()\n            print(data)\n            webview.loadData(data, \"text/html; charset=UTF-8\", nil)\n        end)\n    end)\nend\n\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend\n"
  },
  {
    "path": "lua/ithome/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\n\nlocal Adapter = luajava.bindClass(\"androlua.LuaAdapter\")\nlocal ImageLoader = luajava.bindClass(\"androlua.LuaImageLoader\")\nlocal LuaFragment = luajava.bindClass(\"androlua.LuaFragment\")\nlocal Http = luajava.bindClass(\"androlua.LuaHttp\")\nlocal ITHomeUtils = luajava.bindClass(\"pub.hanks.sample.ITHomeUtils\")\n\n\nfunction readContent(str, pattern, defalut)\n    for content in string.gmatch(str, pattern) do\n        return content\n    end\n    return defalut\nend\n\n\nfunction runOnUiThread(activity, f)\n    activity.runOnUiThread(luajava.createProxy('java.lang.Runnable', {\n        run = f\n    }))\nend\n\n\n\nfunction getData(path, data, adapter, fragment)\n    --  http://api.ithome.com/xml/newslist/news.xml  news_3213df6f23a21dfa.xml\n    --  http://api.ithome.com/xml/slide/news.xml\n    -- <cid>166</cid> 的是广告  含有 live 的是直播\n    local id = ''\n    if #data > 0 then\n        id = '_' .. ITHomeUtils.desEncode(data[#data].newsid)\n    end\n    local url = string.format('http://api.ithome.com/xml/newslist/' .. path, id)\n    Http.request({ url = url }, function(error, code, body)\n        for item in string.gmatch(body, '<item.->(.-)</item>') do\n            local news = {}\n            news.cid = readContent(item, '<cid>(.-)</cid>')\n            if news.cid ~= '166' then\n                news.newsid = readContent(item, '<newsid>(.-)</newsid>', 0)\n                news.title = readContent(item, '<title>%s*<!%[CDATA%[(.-)]]>%s*</title>', 'errorTitle')\n                news.url = readContent(item, '<url>(.-)</url>', 'http://hanks.pub')\n                news.postdate = readContent(item, '<postdate>(.-)</postdate>')\n                news.image = readContent(item, '<image>(.-)</image>')\n                news.description = readContent(item, '<description>%s*<!%[CDATA%[(.-)]]>%s*</description>')\n                news.hitcount = readContent(item, '<hitcount>(.-)</hitcount>')\n                news.commentcount = readContent(item, '<commentcount>(.-)</commentcount>')\n                news.forbidcomment = readContent(item, '<forbidcomment>(.-)</forbidcomment>')\n                data[1 + #data] = news\n            end\n        end\n        runOnUiThread(fragment.getActivity(), function()\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nfunction launchDetail(fragment, newsid)\n    local activity = fragment.getActivity()\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'ithome/activity_news_detail.lua')\n    intent.putExtra(\"newsid\", newsid)\n    activity.startActivity(intent)\nend\n\nfunction newInstance(path)\n\n    -- create view table\n    local layout = {\n        ListView,\n        id = \"listview\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    }\n\n    local item_view = {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"wrap\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"12dp\",\n        paddingTop = \"12dp\",\n        paddingBottom = \"12dp\",\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_gravity = \"center_vertical\",\n            layout_width = \"72dp\",\n            layout_height = \"72dp\",\n        },\n        {\n            TextView,\n            id = \"tv_title\",\n            layout_marginLeft = \"84dp\",\n            layout_width = \"fill\",\n            maxLines = \"2\",\n            lineSpacingMultiplier = '1.2',\n            layout_gravity = \"top\",\n            textSize = \"14sp\",\n            textColor = \"#222222\",\n        },\n        {\n            TextView,\n            id = \"tv_date\",\n            layout_gravity = \"bottom\",\n            layout_marginLeft = \"84dp\",\n            layout_width = \"fill\",\n            textSize = \"12sp\",\n            textColor = \"#aaaaaa\",\n        }\n    }\n\n    local lastId\n    local data = {}\n    local ids = {}\n    local contentView = loadlayout(layout, ids)\n\n    local fragment = LuaFragment.newInstance()\n    local adapter\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onDestroyView = function() end,\n        onDestroy = function() end,\n        onCreateView = function(inflater, container, savedInstanceState)\n            return contentView\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = Adapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data end,\n                getItem = function(position) return nil end,\n                getItemId = function(position) return position end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if position == #data then\n                        print('load more')\n                        getData(path, data, adapter, fragment)\n                    end\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        if parent then\n                            local params = convertView.getLayoutParams()\n                            params.width = parent.getWidth()\n                        end\n                        convertView.setTag(views)\n                    end\n                    local views = convertView.getTag()\n                    local item = data[position]\n                    if item then\n                        ImageLoader.load(views.iv_image, item.image)\n                        views.tv_date.setText(item.postdate)\n                        views.tv_title.setText(item.title)\n                    end\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    local newsid = data[position + 1].newsid\n                    launchDetail(fragment, newsid)\n                end,\n            }))\n            getData(path, data, adapter, fragment)\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}"
  },
  {
    "path": "lua/ithome/info.json",
    "content": "{\n  \"id\": \"pub.hanks.ithome\",\n  \"name\": \"IT之家\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088ea4e40a077?w=150&h=150&f=png&s=1589\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.3\",\n  \"versionCode\": 5,\n  \"desc\": \"快速精选IT新闻\"\n}\n"
  },
  {
    "path": "lua/ithome/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\n\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\n\nlocal fragmentNews = require \"ithome/fragment_news\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#D22222\",\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#D22222\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\n--\n--        <cg n=\"最新\" id=\"101\" s=\"1\" lu=\"http://api.ithome.com/xml/newslist/news.xml\" su=\"http://api.ithome.com/xml/slide/slide.xml\"></cg>\n--        <cg n=\"排行榜\" id=\"102\" s=\"1\" lu=\"http://api.ithome.com/xml/newslist/rank.xml\" su=\"\"></cg>\n--        <cg n=\"三星\" id=\"115\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/sanxing.xml\" su=\"\"></cg>\n--        <cg n=\"华为\" id=\"116\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/huawei.xml\" su=\"\"></cg>\n--        <cg n=\"小米\" id=\"117\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/xiaomi.xml\" su=\"\"></cg>\n--        <cg n=\"魅族\" id=\"118\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/meizu.xml\" su=\"\"></cg>\n--        <cg n=\"OPPO\" id=\"119\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/oppo.xml\" su=\"\"></cg>\n--        <cg n=\"vivo\" id=\"120\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/vivo.xml\" su=\"\"></cg>\n--        <cg n=\"锤子\" id=\"121\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/chuizi.xml\" su=\"\"></cg>\n--        <cg n=\"LG\" id=\"122\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/lg.xml\" su=\"\"></cg>\n--        <cg n=\"联想\" id=\"123\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/lenovo.xml\" su=\"\"></cg>\n--        <cg n=\"一加\" id=\"124\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/yijia.xml\" su=\"\"></cg>\n--        <cg n=\"评测室\" id=\"105\" s=\"1\" lu=\"http://api.ithome.com/xml/newslist/labs.xml\" su=\"http://api.ithome.com/xml/slide/labs.xml\"></cg>\n--        <cg n=\"发布会\" id=\"154\" s=\"1\" lu=\"http://api.ithome.com/xml/newslist/live.xml\" su=\"\"></cg>\n--        <cg n=\"手机\" id=\"103\" s=\"1\" lu=\"http://api.ithome.com/xml/newslist/phone.xml\" su=\"http://api.ithome.com/xml/slide/phone.xml\"></cg>\n--        <cg n=\"数码\" id=\"104\" s=\"1\" lu=\"http://api.ithome.com/xml/newslist/digi.xml\" su=\"http://api.ithome.com/xml/slide/digi.xml\"></cg>\n--        <cg n=\"极客学院\" id=\"151\" s=\"1\" lu=\"http://api.ithome.com/xml/newslist/geek.xml\" su=\"\"></cg>\n--        <cg n=\"VR\" id=\"106\" s=\"1\" lu=\"http://api.ithome.com/xml/newslist/vr.xml\" su=\"http://api.ithome.com/xml/slide/vr.xml\"></cg>\n--        <cg n=\"智能汽车\" id=\"107\" s=\"1\" lu=\"http://api.ithome.com/xml/newslist/auto.xml\" su=\"http://api.ithome.com/xml/slide/auto.xml\"></cg>\n--        <cg n=\"电脑\" id=\"108\" s=\"1\" lu=\"http://api.ithome.com/xml/newslist/pc.xml\" su=\"http://api.ithome.com/xml/slide/pc.xml\"></cg>\n--        <cg n=\"安卓\" id=\"152\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/android.xml\" su=\"http://api.ithome.com/xml/slide/android.xml\"></cg>\n--        <cg n=\"网络焦点\" id=\"111\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/internet.xml\" su=\"http://api.ithome.com/xml/slide/internet.xml\"></cg>\n--        <cg n=\"行业前沿\" id=\"112\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/it.xml\" su=\"http://api.ithome.com/xml/slide/it.xml\"></cg>\n--        <cg n=\"游戏电竞\" id=\"113\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/game.xml\" su=\"http://api.ithome.com/xml/slide/game.xml\"></cg>\n--        <cg n=\"苹果\" id=\"109\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/ios.xml\" su=\"http://api.ithome.com/xml/slide/ios.xml\"></cg>\n--        <cg n=\"Windows\" id=\"110\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/windows.xml\" su=\"http://api.ithome.com/xml/slide/windows.xml\"></cg>\n--        <cg n=\"科普\" id=\"114\" s=\"0\" lu=\"http://api.ithome.com/xml/newslist/discovery.xml\" su=\"http://api.ithome.com/xml/slide/discovery.xml\"></cg>\n\ntable.insert(data.fragments, fragmentNews.newInstance(\"news%s.xml\"))\ntable.insert(data.titles, '最新')\n\ntable.insert(data.fragments, fragmentNews.newInstance(\"android%s.xml\"))\ntable.insert(data.titles, '安卓')\n\ntable.insert(data.fragments, fragmentNews.newInstance(\"ios%s.xml\"))\ntable.insert(data.titles, '苹果')\n\ntable.insert(data.fragments, fragmentNews.newInstance(\"windows%s.xml\"))\ntable.insert(data.titles, 'Windows')\n\ntable.insert(data.fragments, fragmentNews.newInstance(\"game%s.xml\"))\ntable.insert(data.titles, '游戏')\n\ntable.insert(data.fragments, fragmentNews.newInstance(\"it%s.xml\"))\ntable.insert(data.titles, '行业前沿')\n\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0xffd22222)\n    activity.setContentView(loadlayout(layout))\n    viewPager.setAdapter(adapter)\n    tab.setSelectedTabIndicatorColor(0xffffffff)\n    tab.setTabTextColors(0x88ffffff, 0xffffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n"
  },
  {
    "path": "lua/jdly/info.json",
    "content": "{\n  \"id\": \"pub.hanks.jdly\",\n  \"name\": \"绝对领域\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088f6c984a623?w=150&h=150&f=png&s=3498\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 2,\n  \"private\": true,\n  \"desc\": \"绝对领域图库\"\n}\n"
  },
  {
    "path": "lua/jdly/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.StaggeredGridLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\n\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\nlocal data = {}\nlocal adapter\nlocal imageWidth = uihelper.getScreenWidth()\nlocal list = { index = 1, page = 1, urls = {} }\nlocal maxHeight = uihelper.dp2px(640)\nmath.randomseed(os.time())\n--- -然后不断产生随机数\nlist.page = math.floor(math.random() * 100)\n-- create view table\nlocal layout = {\n    RelativeLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        RecyclerView,\n        id = \"recyclerView\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n    {\n        TextView,\n        id = \"tv_loading\",\n        text = \"加载中....\",\n        textSize = \"12sp\",\n        textColor = \"#888888\",\n        layout_margin = \"16dp\",\n        layout_alignParentBottom = true,\n        layout_alignParentRight = true,\n    }\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"200dp\",\n        scaleType = \"fitXY\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_gravity = \"right\",\n        background = \"#88000000\",\n        paddingLeft = \"6dp\",\n        paddingRight = \"6dp\",\n        paddingTop = \"2dp\",\n        paddingBottom = \"2dp\",\n        textSize = \"10sp\",\n        visibility = 8,\n        textColor = \"#aaffffff\",\n    },\n    {\n        View,\n        id = \"layer\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        background = \"@drawable/layout_selector_tran\",\n        clickable = true,\n    },\n}\n\nlocal function fetchData()\n    tv_loading.setVisibility(0)\n\n    if list.index > #list.urls then\n        local u = string.format('http://www.jdlingyu.fun/page/%d/', list.page)\n        for k, _ in pairs(list.urls) do\n            list.urls[k] = nil\n        end\n        LuaHttp.request({ url = u }, function(error, code, body)\n            for url in string.gmatch(body, 'href=\"(http://www.jdlingyu.fun/%d+/)\"') do\n                list.urls[#list.urls + 1] = url\n            end\n            list.index = 1\n            list.page = list.page + 1\n            if list.page > 335 then list.page = 1 end\n            fetchData()\n        end)\n        return\n    end\n    local url = list.urls[list.index]\n    LuaHttp.request({ url = url }, function(error, code, body)\n        list.index = list.index + 1\n        uihelper.runOnUiThread(activity, function()\n            local s = #data\n            for img, w, h in string.gmatch(body, 'data.original=\"(http://wx%d.sinaimg.cn/large/[a-zA-Z0-9_-]+.jpg)\"%s+width=\"(%d+)\"%s+height=\"(%d+)\"') do\n                local item = { url = img, w = w, h = h }\n                item.calcHeight = math.floor(imageWidth * tonumber(item.h) / tonumber(item.w))\n                if item.calcHeight > maxHeight then item.calcHeight = maxHeight end\n                data[#data + 1] = item\n            end\n            tv_loading.setVisibility(8)\n            adapter.notifyItemRangeChanged(s, #data)\n        end)\n    end)\nend\n\nlocal function launchDetail(item)\n    local args = { uris = { item.url }, headers = { 'Referer:http://www.jdlingyu.fun', 'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36' } }\n    PicturePreviewActivity.start(activity, JSON.encode(args))\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.getLayoutParams().width = imageWidth\n            holder.itemView.setTag(views)\n            views.layer.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1\n                launchDetail(data[position])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            views.iv_image.getLayoutParams().height = item.calcHeight\n            LuaImageLoader.load(views.iv_image, item.url)\n            if position == #data then fetchData() end\n        end,\n    }))\n    recyclerView.setLayoutManager(StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL))\n    recyclerView.setAdapter(adapter)\n    fetchData()\nend\n"
  },
  {
    "path": "lua/jike/fragment_feed.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nlocal JSON = require(\"cjson\")\nlocal ImageLoader = import \"androlua.LuaImageLoader\"\nlocal LuaFragment = import(\"androlua.LuaFragment\")\nlocal Http = import \"androlua.LuaHttp\"\nlocal uihelper = require(\"uihelper\")\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.view.View\"\nimport \"android.support.v4.widget.Space\"\nimport \"androlua.widget.ninegride.LuaNineGridView\"\nimport \"androlua.widget.ninegride.LuaNineGridViewAdapter\"\n\nlocal function clearTable(t)\n    for k in pairs(t) do\n        t[k] = nil\n    end\nend\n\nlocal function fetchData(refreshLayout, data, adapter, fragment, reload)\n    local url = string.format('http://app.jike.ruguoapp.com/1.0/newsFeed/list')\n    print(url)\n    local postBody = { trigger = 'user' }\n    if data.loadMoreKey and not reload then\n        postBody.loadMoreKey = data.loadMoreKey\n        postBody.trigger = 'auto'\n    end\n    local options = {\n        url = url,\n        method = 'POST',\n        body = JSON.encode(postBody),\n        headers = {\n            \"Cookie:io=0_Djvr_i0yLPqdsuFnzY; jike:sess.sig=d-IvFa3n5DhxWNim_0gVasNfTP0; jike:feed:latestNormalMessageId=592e495c7a27e200117d35b3; jike:recommendfeed:latestRecCreatedAt=2017-05-31T06:16:06.797Z; jike:sess=eyJfdWlkIjoiNTdmYjc2YTJhNzViY2ExMzAwZjYyMzkyIiwiX3Nlc3Npb25Ub2tlbiI6IkdRTUU0RmNkTHZhNTZlcExXR1BaYURDaDQifQ==; jikeSocketSticky=33b938e0c7b12816f8f2e027067ee82d69975eb2; jike:feed:latestFeedItemId=592e495c7a27e200117d35b3; jike:feed:noContentPullCount=0\"\n        }\n    }\n    Http.request(options, function(error, code, body)\n        if error or code ~= 200 then\n            print(' ================== get data error')\n            return\n        end\n        local json = JSON.decode(body)\n        data.loadMoreKey = json.loadMoreKey\n        if reload then\n            clearTable(data.msg)\n        end\n        for i = 1, #json.data do\n            local type = json.data[i].type\n            if type == 'MESSAGE' then\n                data.msg[#data.msg + 1] = json.data[i]\n            end\n        end\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            refreshLayout.setRefreshing(false)\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\n-- local log = require(\"androlua.common.log\")\n\nlocal function launchDetail(fragment, msg)\n    local activity = fragment.getActivity()\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'ithome/activity_news_detail.lua')\n    intent.putExtra(\"url\", msg.item.linkUrl)\n    activity.startActivity(intent)\nend\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"match\",\n    layout_height = \"match\",\n    orientation = \"vertical\",\n    {\n        SwipeRefreshLayout,\n        id = \"refreshLayout\",\n        {\n            RecyclerView,\n            id = \"recyclerView\",\n            paddingTop = \"25dp\",\n            clipToPadding = false,\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n    },\n}\n\nlocal item_view = require('jike.item_msg')\nlocal item_loading = {\n    LinearLayout,\n    layout_width = \"match\",\n    layout_height = \"72dp\",\n    gravity = \"center\",\n    {\n        ProgressBar,\n        layout_width = \"32dp\",\n        layout_height = \"32dp\",\n    },\n}\n\n\nfunction newInstance()\n\n    local data = { msg = {} }\n    local ids = {}\n    local fragment = LuaFragment.newInstance()\n    local adapter\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onDestroyView = function() end,\n        onDestroy = function() end,\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n                getItemCount = function()\n                    if #data.msg > 0 then return #data.msg + 1\n                    else return 0\n                    end\n                end,\n                getItemViewType = function(position)\n                    if position > 0 and position == #data.msg then return 1 end\n                    return 0\n                end,\n                onCreateViewHolder = function(parent, viewType)\n                    local views = {}\n                    local holder\n                    if viewType == 1 then\n                        holder = LuaRecyclerHolder(loadlayout(item_loading, views, RecyclerView))\n                    else\n                        holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n                        holder.itemView.setTag(views)\n                        holder.itemView.onClick = function(view)\n                            local position = holder.getAdapterPosition() + 1\n                            if position <= #data.msg then\n                                launchDetail(fragment, data.msg[position])\n                            end\n                        end\n                    end\n                    holder.itemView.getLayoutParams().width = parent.getWidth()\n                    return holder\n                end,\n                onBindViewHolder = function(holder, position)\n                    position = position + 1\n                    if (position == #data.msg) then\n                        fetchData(ids.refreshLayout, data, adapter, fragment) -- getdata may call ther lua files\n                        return\n                    end\n                    local msg = data.msg[position]\n                    local views = holder.itemView.getTag()\n                    views.tv_title.setText(msg.item.title or 'error title')\n                    views.tv_content.setText(msg.item.content or '')\n                    views.tv_date.setText(msg.item.updatedAt:sub(1, 10) or '')\n                    views.tv_collect.setText(string.format('%s', msg.item.collectCount))\n                    views.tv_comment.setText(string.format('%s', msg.item.commentCount))\n                    ImageLoader.load(views.iv_image, msg.item.topic.thumbnailUrl)\n                    if msg.item.video then\n                        ImageLoader.load(views.iv_video, msg.item.video.thumbnailUrl)\n                        views.layout_video.setVisibility(0)\n                    else\n                        views.layout_video.setVisibility(8)\n                    end\n\n                    if msg.item.pictureUrls and #msg.item.pictureUrls > 0 then\n                        local pictures = msg.item.pictureUrls\n                        local urls = {}\n                        local len = #pictures\n                        for i = 1, len do\n                            if len == 1 then\n                                urls[i] = pictures[i].picUrl\n                                views.iv_nine_grid.setSingleImgSize(pictures[i].width, pictures[i].height)\n                            else urls[i] = pictures[i].thumbnailUrl\n                            end\n                        end\n\n                        views.iv_nine_grid.setVisibility(0)\n                        if views.iv_nine_grid.getAdapter() == nil then\n                            views.iv_nine_grid.setAdapter(LuaNineGridViewAdapter(luajava.createProxy('androlua.widget.ninegride.LuaNineGridViewAdapter$AdapterCreator', {\n                                onDisplayImage = function(context, imageView, url)\n                                    ImageLoader.load(imageView, url)\n                                end,\n                                onItemImageClick = function(context, imageView, index, list)\n                                    print(list.get(index))\n                                end\n                            })))\n                        end\n                        views.iv_nine_grid.setImagesData(urls)\n                    else\n                        views.iv_nine_grid.setVisibility(8)\n                    end\n                end,\n            }))\n            ids.recyclerView.setLayoutManager(LinearLayoutManager(fragment.getActivity()))\n            ids.recyclerView.setAdapter(adapter)\n            ids.refreshLayout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    fetchData(ids.refreshLayout, data, adapter, fragment, true)\n                end\n            }))\n            ids.refreshLayout.setRefreshing(true)\n            fetchData(ids.refreshLayout, data, adapter, fragment) -- getdata may call ther lua files\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}"
  },
  {
    "path": "lua/jike/fragment_hot.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\n\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.view.View\"\nimport \"android.support.v4.widget.Space\"\nimport \"androlua.widget.ninegride.LuaNineGridView\"\nimport \"androlua.widget.ninegride.LuaNineGridViewAdapter\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"androlua.widget.webview.WebViewActivity\"\n\nlocal JSON = require(\"cjson\")\nlocal uihelper = require(\"uihelper\")\n\nlocal function clearTable(t)\n    for k in pairs(t) do\n        t[k] = nil\n    end\nend\n\nlocal function fetchData(refreshLayout, data, adapter, fragment, reload)\n    local url = string.format('http://app.jike.ruguoapp.com/1.0/users/messages/listPopularByTag?tag=ALL')\n    local options = {\n        url = url,\n        headers = {\n            \"Cookie:io=0_Djvr_i0yLPqdsuFnzY; jike:sess.sig=d-IvFa3n5DhxWNim_0gVasNfTP0; jike:feed:latestNormalMessageId=592e495c7a27e200117d35b3; jike:recommendfeed:latestRecCreatedAt=2017-05-31T06:16:06.797Z; jike:sess=eyJfdWlkIjoiNTdmYjc2YTJhNzViY2ExMzAwZjYyMzkyIiwiX3Nlc3Npb25Ub2tlbiI6IkdRTUU0RmNkTHZhNTZlcExXR1BaYURDaDQifQ==; jikeSocketSticky=33b938e0c7b12816f8f2e027067ee82d69975eb2; jike:feed:latestFeedItemId=592e495c7a27e200117d35b3; jike:feed:noContentPullCount=0\"\n        }\n    }\n    LuaHttp.request(options, function(error, code, body)\n        if error or code ~= 200 then\n            print(' ================== get data error')\n            return\n        end\n        local arr = JSON.decode(body).data\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                clearTable(data.msg)\n            end\n            for i = 1, #arr do\n                data.msg[#data.msg + 1] = arr[i]\n            end\n            refreshLayout.setRefreshing(false)\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nlocal log = require(\"log\")\n\nlocal function launchDetail(fragment, msg)\n    local activity = fragment.getActivity()\n    --log.print_r(msg)\n    local url = 'https://m.okjike.com/originalPosts/' .. msg.id\n    WebViewActivity.start(activity, url, 0xFFffe411)\nend\n\nlocal function launchPicturePreview(fragment, msg, index)\n    local urls = {}\n    for i = 1, #msg.pictures do\n        urls[i] = msg.pictures[i].picUrl\n    end\n    local data = {\n        uris = urls,\n        currentIndex = index\n    }\n    PicturePreviewActivity.start(fragment.getActivity(), JSON.encode(data))\nend\n\nfunction newInstance()\n\n    -- create view table\n    local layout = {\n        LinearLayout,\n        layout_width = \"match\",\n        layout_height = \"match\",\n        orientation = \"vertical\",\n        {\n            SwipeRefreshLayout,\n            id = \"refreshLayout\",\n            layout_width = \"match\",\n            {\n                RecyclerView,\n                id = \"recyclerView\",\n                paddingTop = \"25dp\",\n                clipToPadding = false,\n                layout_width = \"fill\",\n                layout_height = \"fill\",\n            },\n        },\n    }\n\n    local item_view = require('jike.item_msg')\n    local data = { msg = {} }\n    local ids = {}\n    local fragment = LuaFragment.newInstance()\n    local adapter\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n                getItemCount = function()\n                    return #data.msg\n                end,\n                getItemViewType = function(position)\n                    return 0\n                end,\n                onCreateViewHolder = function(parent, viewType)\n                    local views = {}\n                    local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n                    holder.itemView.getLayoutParams().width = parent.getWidth()\n                    holder.itemView.setTag(views)\n                    holder.itemView.onClick = function(view)\n                        local position = holder.getAdapterPosition() + 1\n                        launchDetail(fragment, data.msg[position])\n                    end\n                    return holder\n                end,\n                onBindViewHolder = function(holder, position)\n                    position = position + 1\n                    local msg = data.msg[position]\n                    local views = holder.itemView.getTag()\n                    views.tv_title.setText(msg.topic.content or 'error title')\n                    views.tv_content.setText(msg.content or '')\n                    views.tv_date.setText(msg.createdAt:sub(1, 10) or '')\n                    LuaImageLoader.loadWithRadius(views.iv_image, 3, msg.topic.squarePicture.thumbnailUrl)\n                    if msg.video then\n                        views.layout_video.setVisibility(0)\n                        LuaImageLoader.load(views.iv_video, msg.video.thumbnailUrl)\n                    else\n                        views.layout_video.setVisibility(8)\n                    end\n                    views.tv_collect.setText(string.format('%d', msg.likeCount))\n                    views.tv_comment.setText(string.format('%d', msg.commentCount))\n\n                    if msg.pictures and #msg.pictures > 0 then\n                        local pictures = msg.pictures\n                        local urls = {}\n                        local len = #pictures\n                        for i = 1, len do\n                            if len == 1 then\n                                urls[i] = pictures[i].picUrl\n                                views.iv_nine_grid.setSingleImgSize(pictures[i].width, pictures[i].height)\n                            else urls[i] = pictures[i].thumbnailUrl\n                            end\n                        end\n                        views.iv_nine_grid.setVisibility(0)\n                        views.iv_nine_grid.setAdapter(LuaNineGridViewAdapter(luajava.createProxy('androlua.widget.ninegride.LuaNineGridViewAdapter$AdapterCreator', {\n                            onDisplayImage = function(context, imageView, url)\n                                LuaImageLoader.load(imageView, url)\n                            end,\n                            onItemImageClick = function(context, imageView, index, list)\n                                launchPicturePreview(fragment, msg, index)\n                            end\n                        })))\n                        views.iv_nine_grid.setImagesData(urls)\n                    else\n                        views.iv_nine_grid.setVisibility(8)\n                    end\n                end,\n            }))\n            ids.recyclerView.setLayoutManager(LinearLayoutManager(fragment.getActivity()))\n            ids.recyclerView.setAdapter(adapter)\n            ids.refreshLayout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    fetchData(ids.refreshLayout, data, adapter, fragment, true)\n                end\n            }))\n            ids.refreshLayout.setRefreshing(true)\n            fetchData(ids.refreshLayout, data, adapter, fragment) -- getdata may call ther lua files\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/jike/fragment_recomend.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\n\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.view.View\"\nimport \"android.support.v4.widget.Space\"\nimport \"androlua.widget.ninegride.LuaNineGridView\"\nimport \"androlua.widget.ninegride.LuaNineGridViewAdapter\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"androlua.widget.webview.WebViewActivity\"\n\nlocal JSON = require(\"cjson\")\nlocal uihelper = require(\"uihelper\")\n\n\nlocal function clearTable(t)\n    for k in pairs(t) do\n        t[k] = nil\n    end\nend\n\nlocal function fetchData(refreshLayout, data, adapter, fragment, reload)\n    local url = string.format('http://app.jike.ruguoapp.com/1.0/recommendFeed/list')\n    local postBody = { trigger = 'user' }\n    if data.loadMoreKey and not reload then\n        postBody.loadMoreKey = data.loadMoreKey\n        postBody.trigger = 'auto'\n    end\n    local options = {\n        url = url,\n        method = 'POST',\n        body = JSON.encode(postBody),\n        headers = {\n            \"Cookie:io=0_Djvr_i0yLPqdsuFnzY; jike:sess.sig=d-IvFa3n5DhxWNim_0gVasNfTP0; jike:feed:latestNormalMessageId=592e495c7a27e200117d35b3; jike:recommendfeed:latestRecCreatedAt=2017-05-31T06:16:06.797Z; jike:sess=eyJfdWlkIjoiNTdmYjc2YTJhNzViY2ExMzAwZjYyMzkyIiwiX3Nlc3Npb25Ub2tlbiI6IkdRTUU0RmNkTHZhNTZlcExXR1BaYURDaDQifQ==; jikeSocketSticky=33b938e0c7b12816f8f2e027067ee82d69975eb2; jike:feed:latestFeedItemId=592e495c7a27e200117d35b3; jike:feed:noContentPullCount=0\"\n        }\n    }\n    LuaHttp.request(options, function(error, code, body)\n        if error or code ~= 200 then\n            print(' ================== get data error')\n            return\n        end\n        local json = JSON.decode(body)\n        data.loadMoreKey = json.loadMoreKey\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                clearTable(data.msg)\n            end\n            for i = 1, #json.data do\n                local type = json.data[i].type\n                if type == 'MESSAGE_RECOMMENDATION' then\n                    data.msg[#data.msg + 1] = json.data[i]\n                end\n            end\n            refreshLayout.setRefreshing(false)\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\n-- local log = require(\"log\")\n\nlocal function launchDetail(fragment, msg)\n    local activity = fragment.getActivity()\n    -- log.print_r(msg)\n    if msg and msg.item and msg.item.linkUrl then\n        WebViewActivity.start(activity, msg.item.linkUrl, 0xF12979FB)\n        return\n    end\n\n    activity.toast('没有 url 可以打开')\nend\n\nlocal function launchPicturePreview(fragment, msg, index)\n    local urls = {}\n    for i = 1, #msg.item.pictureUrls do\n        urls[i] = msg.item.pictureUrls[i].picUrl\n    end\n    local data = {\n        uris = urls,\n        currentIndex = index\n    }\n    PicturePreviewActivity.start(fragment.getActivity(), JSON.encode(data))\nend\n\nfunction newInstance()\n\n    -- create view table\n    local layout = {\n        LinearLayout,\n        layout_width = \"match\",\n        layout_height = \"match\",\n        orientation = \"vertical\",\n        {\n            SwipeRefreshLayout,\n            layout_width = \"match\",\n            id = \"refreshLayout\",\n            {\n                RecyclerView,\n                id = \"recyclerView\",\n                paddingTop = \"25dp\",\n                clipToPadding = false,\n                layout_width = \"fill\",\n                layout_height = \"fill\",\n            },\n        },\n    }\n\n    local item_view = require('jike.item_msg')\n    local item_loading = {\n        LinearLayout,\n        layout_width = \"match\",\n        layout_height = \"72dp\",\n        gravity = \"center\",\n        {\n            ProgressBar,\n            layout_width = \"32dp\",\n            layout_height = \"32dp\",\n        },\n    }\n    local data = { msg = {} }\n    local ids = {}\n    local fragment = LuaFragment.newInstance()\n    local adapter\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n                getItemCount = function()\n                    if #data.msg > 0 then return #data.msg + 1\n                    else return 0\n                    end\n                end,\n                getItemViewType = function(position)\n                    if position > 0 and position == #data.msg then return 1 end\n                    return 0\n                end,\n                onCreateViewHolder = function(parent, viewType)\n                    local views = {}\n                    local holder\n                    if viewType == 1 then\n                        holder = LuaRecyclerHolder(loadlayout(item_loading, views, RecyclerView))\n                    else\n                        holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n                        holder.itemView.setTag(views)\n                        holder.itemView.onClick = function(view)\n                            local position = holder.getAdapterPosition() + 1\n                            if position <= #data.msg then\n                                launchDetail(fragment, data.msg[position])\n                            end\n                        end\n                    end\n                    holder.itemView.getLayoutParams().width = parent.getWidth()\n                    return holder\n                end,\n                onBindViewHolder = function(holder, position)\n                    position = position + 1\n                    if (position == #data.msg + 1) then\n                        fetchData(ids.refreshLayout, data, adapter, fragment) -- getdata may call ther lua files\n                        return\n                    end\n                    local msg = data.msg[position]\n                    local views = holder.itemView.getTag()\n                    if views == nil then return end\n                    views.tv_title.setText(msg.item.title or 'error title')\n                    views.tv_content.setText(msg.item.content or '')\n                    views.tv_date.setText(msg.item.updatedAt:sub(1, 10) or '')\n                    views.tv_collect.setText(string.format('%s', msg.item.collectCount))\n                    views.tv_comment.setText(string.format('%s', msg.item.commentCount))\n                    LuaImageLoader.load(views.iv_image, msg.item.topic.thumbnailUrl)\n                    if msg.item.video then\n                        LuaImageLoader.load(views.iv_video, msg.item.video.thumbnailUrl)\n                        views.layout_video.setVisibility(0)\n                    else\n                        views.layout_video.setVisibility(8)\n                    end\n                    if msg.item.pictureUrls and #msg.item.pictureUrls > 0 then\n                        local pictures = msg.item.pictureUrls\n                        local urls = {}\n                        local len = #pictures\n                        for i = 1, len do\n                            if len == 1 then\n                                urls[i] = pictures[i].middlePicUrl\n                                views.iv_nine_grid.setSingleImgSize(pictures[i].width, pictures[i].height)\n                            else urls[i] = pictures[i].thumbnailUrl\n                            end\n                        end\n\n                        views.iv_nine_grid.setVisibility(0)\n                        views.iv_nine_grid.setAdapter(LuaNineGridViewAdapter(luajava.createProxy('androlua.widget.ninegride.LuaNineGridViewAdapter$AdapterCreator', {\n                            onDisplayImage = function(context, imageView, url)\n                                LuaImageLoader.load(imageView, url)\n                            end,\n                            onItemImageClick = function(context, imageView, index, list)\n                                launchPicturePreview(fragment, msg, index)\n                            end\n                        })))\n                        views.iv_nine_grid.setImagesData(urls)\n                    else\n                        views.iv_nine_grid.setVisibility(8)\n                    end\n                end,\n            }))\n            ids.recyclerView.setLayoutManager(LinearLayoutManager(fragment.getActivity()))\n            ids.recyclerView.setAdapter(adapter)\n            ids.refreshLayout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    fetchData(ids.refreshLayout, data, adapter, fragment, true)\n                end\n            }))\n            ids.refreshLayout.setRefreshing(true)\n            fetchData(ids.refreshLayout, data, adapter, fragment) -- getdata may call ther lua files\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/jike/info.json",
    "content": "{\n  \"id\": \"pub.hanks.jike\",\n  \"name\": \"即刻\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088fd40e849d7?w=150&h=150&f=png&s=1924\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.5\",\n  \"versionCode\": 6,\n  \"desc\": \"即刻热门的信息流\"\n}\n"
  },
  {
    "path": "lua/jike/item_msg.lua",
    "content": "return {\n    LinearLayout,\n    layout_width = \"fill\",\n    paddingTop = \"16dp\",\n    orientation = \"vertical\",\n    background = \"@drawable/layout_se\",\n    -- head\n    {\n        FrameLayout,\n        layout_width = \"match\",\n        layout_height = \"36dp\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"16dp\",\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_width = \"36dp\",\n            layout_height = \"36dp\",\n            scaleType = \"centerCrop\"\n        },\n        {\n            TextView,\n            id = \"tv_title\",\n            layout_marginLeft = \"44dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            maxLines = \"1\",\n            ellipsize = \"end\",\n            textSize = \"13sp\",\n            textColor = \"#4888B0\",\n        },\n        {\n            TextView,\n            id = \"tv_date\",\n            layout_gravity = \"bottom\",\n            layout_marginLeft = \"44dp\",\n            layout_width = \"fill\",\n            maxLines = \"1\",\n            textSize = \"11sp\",\n            textColor = \"#BFBFBF\",\n        },\n    },\n    -- content\n    {\n        TextView,\n        id = \"tv_content\",\n        layout_width = \"fill\",\n        layout_marginLeft = \"16dp\",\n        layout_marginRight = \"16dp\",\n        layout_marginTop = \"12dp\",\n        lineSpacingMultiplier = '1.3',\n        textSize = \"14sp\",\n        textColor = \"#404040\",\n    },\n    -- pictures\n    {\n        LuaNineGridView,\n        id = \"iv_nine_grid\",\n        layout_width = \"match\",\n        layout_height = \"200dp\",\n        gap = \"4dp\",\n        maxSize = 9,\n        visibility = \"gone\",\n        layout_marginTop = \"12dp\",\n        layout_marginLeft = \"16dp\",\n        layout_marginRight = \"16dp\",\n    },\n\n    -- video\n    {\n        FrameLayout,\n        id = \"layout_video\",\n        layout_width = \"match\",\n        layout_height = \"200dp\",\n        layout_marginTop = \"12dp\",\n        layout_marginLeft = \"16dp\",\n        layout_marginRight = \"16dp\",\n        {\n            ImageView,\n            id = \"iv_video\",\n            layout_width = \"match\",\n            layout_height = \"200dp\",\n            scaleType = \"centerCrop\"\n        },\n        {\n            View,\n            layout_height = \"match\",\n            layout_width = \"match\",\n            background = \"#66000000\",\n        },\n        {\n            ImageView,\n            layout_gravity = \"center\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            src = \"#jike/img/ic_video_play.png\",\n        },\n    },\n    -- foot\n    {\n        LinearLayout,\n        layout_width = \"match\",\n        layout_height = \"56dp\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"16dp\",\n        gravity = \"center_vertical\",\n        orientation = \"horizontal\",\n        {\n            ImageView,\n            layout_width = \"20dp\",\n            layout_height = \"20dp\",\n            src = \"#jike/img/ic_like_border.png\",\n        },\n        {\n            TextView,\n            id = \"tv_collect\",\n            layout_width = \"70dp\",\n            paddingLeft = \"4dp\",\n            textSize = \"12sp\",\n            textColor = \"#BFBFBF\",\n        },\n        {\n            ImageView,\n            layout_width = \"20dp\",\n            layout_height = \"20dp\",\n            src = \"#jike/img/ic_comment.png\"\n        },\n        {\n            TextView,\n            id = \"tv_comment\",\n            paddingLeft = \"4dp\",\n            layout_width = \"70dp\",\n            textSize = \"12sp\",\n            textColor = \"#BFBFBF\",\n        },\n        {\n            ImageView,\n            layout_width = \"20dp\",\n            layout_height = \"20dp\",\n            src = \"#jike/img/ic_share.png\"\n        },\n    },\n    {\n        View,\n        layout_height = \"8dp\",\n        layout_width = \"fill\",\n        background = \"#F0F3F5\",\n    }\n}\n"
  },
  {
    "path": "lua/jike/main.lua",
    "content": "require \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.support.design.widget.BottomNavigationView\"\nimport \"androlua.widget.viewpager.NoScrollViewPager\"\nimport \"androlua.utils.ColorStateListFactory\"\nimport \"androlua.LuaDrawable\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\n\n-- local feedFragment = require(\"jike.fragment_feed\")\nlocal hotFragment = require(\"jike.fragment_hot\")\n\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    {\n        NoScrollViewPager,\n        id = \"viewPager\",\n        layout_width = \"fill\",\n        layout_weight = 1,\n        background = \"#ffffff\",\n    },\n}\n\nlocal data = {\n    titles = { \"热门\", \"热门\", \"订阅\" },\n    -- fragments = {recommendFragment.newInstance(), hotFragment.newInstance(), feedFragment.newInstance()},\n    fragments = { hotFragment.newInstance() },\n}\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    -- bottomView\n    -- bottomView.setItemTextColor(ColorStateListFactory.newInstance(0xFFC7C7C7, 0xFF1E1E1E))\n    -- bottomView.setItemIconTintList(ColorStateListFactory.newInstance(0xFFC7C7C7, 0xFF1E1E1E))\n    -- local recommentDrawable = LuaDrawable.create('jike/img/recoment.png')\n    -- local hotDrawable = LuaDrawable.create('jike/img/hot.png')\n    -- local feedDrawable = LuaDrawable.create('jike/img/feed.png')\n    -- bottomView.getMenu().add(\"推荐\").setIcon(recommentDrawable)\n    -- bottomView.getMenu().add(\"热门\").setIcon(hotDrawable)\n    -- bottomView.getMenu().add(\"订阅\").setIcon(feedDrawable)\n    -- bottomView.setOnNavigationItemSelectedListener(luajava.createProxy('android.support.design.widget.BottomNavigationView$OnNavigationItemSelectedListener', {\n    --     onNavigationItemSelected = function(item)\n    --         local title = item.getTitle()\n    --         if title == \"推荐\" then viewPager.setCurrentItem(0, false) end\n    --         if title == \"热门\" then viewPager.setCurrentItem(1, false) end\n    --         if title == \"订阅\" then viewPager.setCurrentItem(2, false) end\n    --         return true\n    --     end\n    -- }))\n\n    -- viewpager\n    viewPager.setAdapter(adapter)\nend\n"
  },
  {
    "path": "lua/magmoe-cos/info.json",
    "content": "{\n  \"id\": \"pub.hanks.magmoe-cos\",\n  \"name\": \"moe cos\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088b4ae47d08e?w=150&h=150&f=png&s=3459\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.2\",\n  \"versionCode\": 4,\n  \"desc\": \"cosplay ，来源：mag.moe\"\n}\n"
  },
  {
    "path": "lua/magmoe-cos/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.StaggeredGridLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\n\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\nlocal data = {}\nlocal adapter\nlocal imageWidth = uihelper.getScreenWidth() / 2\nlocal list = { index = 1, page = 1, urls = {} }\nlocal maxHeight = uihelper.dp2px(400)\n\nmath.randomseed(os.time())\n--- -然后不断产生随机数\nlist.page = math.floor(math.random() * 240)\n-- create view table\nlocal layout = {\n    RelativeLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        RecyclerView,\n        id = \"recyclerView\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n    {\n        TextView,\n        id = \"tv_loading\",\n        text = \"加载中....\",\n        textSize = \"12sp\",\n        textColor = \"#888888\",\n        layout_margin = \"16dp\",\n        layout_alignParentBottom = true,\n        layout_alignParentRight = true,\n    }\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"200dp\",\n        scaleType = \"fitXY\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_gravity = \"right\",\n        background = \"#88000000\",\n        paddingLeft = \"6dp\",\n        paddingRight = \"6dp\",\n        paddingTop = \"2dp\",\n        paddingBottom = \"2dp\",\n        textSize = \"10sp\",\n        visibility = 8,\n        textColor = \"#aaffffff\",\n    },\n    {\n        View,\n        id = \"layer\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        background = \"@drawable/layout_selector_tran\",\n        clickable = true,\n    },\n}\n\nlocal function fetchData()\n    tv_loading.setVisibility(0)\n    if list.index > #list.urls then\n        local u = string.format('https://mag.moe/category/cosplay/page/%d', list.page)\n        if list.page == 1 then u = 'https://mag.moe/category/cosplay' end\n        for k, _ in pairs(list.urls) do\n            list.urls[k] = nil\n        end\n        LuaHttp.request({ url = u,headers={\n            'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36'\n        } }, function(error, code, body)\n            for url in string.gmatch(body, '<a href=\"(https://mag.moe/%d+)\"><') do\n                list.urls[#list.urls + 1] = url\n            end\n            list.index = 1\n            list.page = list.page + 1\n            if list.page > 244 then list.page = 1 end\n            fetchData()\n        end)\n        return\n    end\n\n    local url = list.urls[list.index]\n    LuaHttp.request({ url = url ,headers={\n        'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36'\n    }}, function(error, code, body)\n        list.index = list.index + 1\n        uihelper.runOnUiThread(activity, function()\n            local s = #data\n            for img, w, h in string.gmatch(body, '(https://mmxv.imgmoe.com/.-)\".-width=\"(%d+)\" height=\"(%d+)\"') do\n                local item = { url = img, w = w, h = h }\n                item.calcHeight = math.floor(imageWidth * tonumber(item.h) / tonumber(item.w))\n                if item.calcHeight > maxHeight then item.calcHeight = maxHeight end\n                data[#data + 1] = item\n            end\n            tv_loading.setVisibility(8)\n            adapter.notifyItemRangeChanged(s, #data)\n        end)\n    end)\nend\n\nlocal function launchDetail(item)\n    local args = { uris = { item.url }, headers = { 'Referer:https://mag.moe', 'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36' } }\n    PicturePreviewActivity.start(activity, JSON.encode(args))\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.getLayoutParams().width = imageWidth\n            holder.itemView.setTag(views)\n            views.layer.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1\n                launchDetail(data[position])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            views.iv_image.getLayoutParams().height = item.calcHeight\n            LuaImageLoader.load(views.iv_image, item.url)\n            if position == #data then fetchData() end\n        end,\n    }))\n    recyclerView.setLayoutManager(StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL))\n    recyclerView.setAdapter(adapter)\n    fetchData()\nend\n"
  },
  {
    "path": "lua/magmoe-image/info.json",
    "content": "{\n  \"id\": \"pub.hanks.magmoe-image\",\n  \"name\": \"MOE二次元\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088b4ae47d08e?w=150&h=150&f=png&s=3459\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.2\",\n  \"versionCode\": 4,\n  \"desc\": \"质量很好的二次元图, mag.moe\"\n}\n"
  },
  {
    "path": "lua/magmoe-image/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.StaggeredGridLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\n\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\nlocal data = {}\nlocal adapter\nlocal imageWidth = uihelper.getScreenWidth() / 2\nlocal list = { index = 1, page = 1, urls = {} }\nlocal maxHeight = uihelper.dp2px(400)\n\nmath.randomseed(os.time())\n--- -然后不断产生随机数\nlist.page = math.floor(math.random() * 256)\n\n-- create view table\nlocal layout = {\n    RelativeLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        RecyclerView,\n        id = \"recyclerView\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n    {\n        TextView,\n        id = \"tv_loading\",\n        text = \"加载中....\",\n        textSize = \"12sp\",\n        textColor = \"#888888\",\n        layout_margin = \"16dp\",\n        layout_alignParentBottom = true,\n        layout_alignParentRight = true,\n    }\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"200dp\",\n        scaleType = \"fitXY\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_gravity = \"right\",\n        background = \"#88000000\",\n        paddingLeft = \"6dp\",\n        paddingRight = \"6dp\",\n        paddingTop = \"2dp\",\n        paddingBottom = \"2dp\",\n        textSize = \"10sp\",\n        visibility = 8,\n        textColor = \"#aaffffff\",\n    },\n    {\n        View,\n        id = \"layer\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        background = \"@drawable/layout_selector_tran\",\n        clickable = true,\n    },\n}\n\nlocal function fetchData()\n    tv_loading.setVisibility(0)\n    if list.index > #list.urls then\n        local u = string.format('https://mag.moe/category/images/page/%d', list.page)\n        if list.page == 1 then u = 'https://mag.moe/category/images' end\n        for k, _ in pairs(list.urls) do\n            list.urls[k] = nil\n        end\n        print(u)\n        LuaHttp.request({\n            url = u, \n            headers={\n                'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36'\n            } \n        }, function(error, code, body)\n            print(error, code,body)\n            for url in string.gmatch(body, '<a href=\"(https://mag.moe/%d+)\">') do\n                print(url)\n                list.urls[#list.urls + 1] = url\n            end\n            list.index = 1\n            list.page = list.page + 1\n            if list.page > 256 then list.page = 1 end\n            fetchData()\n        end)\n        return\n    end\n\n    local url = list.urls[list.index]\n    LuaHttp.request({ url = url,\n        headers={\n            'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36'\n        } \n    }, function(error, code, body)\n        list.index = list.index + 1\n        uihelper.runOnUiThread(activity, function()\n            local s = #data\n            for img, w, h in string.gmatch(body, '(https://mmxv.imgmoe.com/.-)\".-width=\"(%d+)\" height=\"(%d+)\"') do\n                local item = { url = img, w = w, h = h }\n                item.calcHeight = math.floor(imageWidth * tonumber(item.h) / tonumber(item.w))\n                if item.calcHeight > maxHeight then item.calcHeight = maxHeight end\n                data[#data + 1] = item\n            end\n            tv_loading.setVisibility(8)\n            adapter.notifyItemRangeChanged(s, #data)\n        end)\n    end)\nend\n\nlocal function launchDetail(item)\n    local args = { uris = { item.url }, headers = { 'Referer:https://mag.moe', 'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Safari/537.36' } }\n    PicturePreviewActivity.start(activity, JSON.encode(args))\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.getLayoutParams().width = imageWidth\n            holder.itemView.setTag(views)\n            views.layer.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1\n                launchDetail(data[position])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            views.iv_image.getLayoutParams().height = item.calcHeight\n            LuaImageLoader.load(views.iv_image, item.url)\n            if position == #data then fetchData() end\n        end,\n    }))\n    recyclerView.setLayoutManager(StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL))\n    recyclerView.setAdapter(adapter)\n    fetchData()\nend\n"
  },
  {
    "path": "lua/notead/info.json",
    "content": "{\n  \"id\": \"pub.hanks.note_pro\",\n  \"name\": \"便签Pro\",\n  \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1ftf62owi8wj2040040wec.jpg\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.0\",\n  \"versionCode\": 1,\n  \"private\": true,\n  \"desc\": \"便签 Pro 版本获取\"\n}\n"
  },
  {
    "path": "lua/notead/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.net.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"android.graphics.BitmapFactory\"\nimport \"java.io.File\"\n\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    gravity = \"center_horizontal\",\n    background = \"#ffffff\",\n    orientation = \"vertical\",\n    {\n        ImageView,\n        id = \"logo\",\n        layout_width = \"72dp\",\n        layout_height = \"72dp\",\n        layout_marginTop = \"70dp\",\n    },\n    {\n        TextView,\n        layout_width = \"200dp\",\n        layout_height = \"40dp\",\n        gravity = \"center\",\n        text = \"Note Pro\",\n        textColor = \"#333333\",\n        textSize = \"12sp\"\n    },\n    {\n        TextView,\n        layout_width = \"wrap_content\",\n        layout_height = \"wrap_content\",\n        layout_marginTop = \"48dp\",\n        lineSpacingMultiplier = \"2.5\",\n        text = \"☑ 纯净无广告\\n☑ 更多的布局样式\\n☑ 自定义主背景\\n☑ 便签置顶功能\\n☑ 优先体验新功能\\n☑ 支持便签项目长期开发\",\n        textColor = \"#333333\",\n        textSize = \"14sp\",\n    },\n    {\n        TextView,\n        id = \"btn_get_pro\",\n        layout_width = \"104dp\",\n        layout_height = \"40dp\",\n        layout_gravity = \"center\",\n        layout_marginTop = \"56dp\",\n        background = \"#C13D34\",\n        elevation = \"2dp\",\n        gravity = \"center\",\n        text = \"Get\",\n        textColor = \"#ffffff\",\n        textSize = \"16sp\",\n    },\n}\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    LuaImageLoader.load(logo, \"http://ww1.sinaimg.cn/large/8c9b876fly1ftf62owi8wj2040040wec.jpg\")\n    btn_get_pro.onClick = function()\n        -- Toast.makeText(activity,\"222\",0).show()\n        pcall(function()\n            local intent = Intent(Intent.ACTION_VIEW)\n            intent.setData(Uri.parse(\"market://details?id=xyz.hanks.note.pro\"))\n            activity.startActivity(intent)\n        end)\n    end\nend\n"
  },
  {
    "path": "lua/packwap/info.json",
    "content": "{\n  \"id\": \"pub.hanks.packwap\",\n  \"name\": \"网页转插件\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088aa62abd550?w=150&h=150&f=png&s=2811\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0\",\n  \"versionCode\": 2,\n  \"desc\": \"将网页应用打包成插件\"\n}\n"
  },
  {
    "path": "lua/packwap/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- qiqu\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaWebView\"\nimport \"android.os.Build\"\nimport \"android.view.View\"\nimport \"android.support.v7.widget.AppCompatSeekBar\"\nimport \"android.support.design.widget.FloatingActionButton\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.animation.ValueAnimator\"\nimport \"java.lang.String\"\nimport \"java.io.File\"\nimport \"java.io.FileOutputStream\"\nimport \"android.graphics.Canvas\"\nimport \"android.graphics.Bitmap\"\nimport \"android.graphics.Paint\"\nimport \"android.graphics.Rect\"\nlocal CompressFormat = import \"android.graphics.Bitmap$CompressFormat\"\nlocal Config = import \"android.graphics.Bitmap$Config\"\n\nlocal JSON = require \"cjson\"\nlocal Orientation = import \"android.graphics.drawable.GradientDrawable$Orientation\"\nlocal colors = luajava.createArray(\"int\", { 0xFF72A3FF, 0xFF607dff })\nlocal gd = GradientDrawable(Orientation.TOP_BOTTOM, colors)\nmath.randomseed(os.time())\n\nlocal colors = {\n    0xFF131313, 0xFFD90C17, 0xFF33BB68, 0xFF3EA6FC, 0xFFE96138, 0xFFFDA236, 0xFF1E89E9, 0xFFF13525,\n    0xFF3EC0D5, 0xFF1EBBA5, 0xFF3273EC, 0xFF22D926, 0xFFA630BF\n}\n\nlocal luaTemp = [[\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaWebView\"\nlocal layout = {\n    LinearLayout, orientation = \"vertical\", layout_width = \"fill\", layout_height = \"fill\", statusBarColor = \"{ssColor}\",\n    { LuaWebView, id = \"webview\", layout_width = \"fill\",layout_height = \"fill\", }\n}\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    webview.loadUrl(\"{url}\")\nend\n\nfunction onBackPressed()\n    if webview.canGoBack() then webview.goBack() return true end\n    return false\nend\n\nfunction onDestroy()\n    pcall(function() webview.release() end)\nend\n]]\n\n\nlocal function write(filePath, txt)\n    pcall(function()\n        local file = File(filePath)\n        file.getParentFile().mkdirs()\n        local f = io.open(filePath, 'wb')\n        f:write(txt)\n        f:close()\n    end)\nend\n\nlocal function drawLogo(txt, filePath, bgColor)\n    local c = '氢'\n    if txt then\n        c = String(txt).substring(0, 1)\n    end\n    if bgColor == 0x33000000 then bgColor = colors[math.random(#colors)] end\n\n    local file = File(filePath)\n    file.getParentFile().mkdirs()\n    local bm = Bitmap.createBitmap(100, 100, Config.RGB_565)\n    local canvas = Canvas(bm)\n    canvas.drawColor(bgColor)\n    local mPaint = Paint(1)\n    mPaint.setTextSize(40)\n    mPaint.setColor(0xFFFFFFFF)\n    local bounds = Rect()\n    mPaint.getTextBounds(c, 0, 1, bounds)\n    canvas.drawText(c, 47 - bounds.width() / 2, 47 + bounds.height() / 2, mPaint)\n    local stream = FileOutputStream(file)\n    bm.compress(CompressFormat.PNG, 100, stream)\n    stream.close()\nend\n\nlocal function pack(params)\n    if params == nil or params.url == nil or params.name == nil then\n        return\n    end\n\n    local dirName = tostring(os.time())\n    local pluginId = 'pub.hydrogen' .. dirName\n\n    local infoPath = string.format('%s/%s/info.json', luajava.luaextdir, dirName)\n    local luaPath = string.format('%s/%s/main.lua', luajava.luaextdir, dirName)\n    local logoPath = string.format('%s/%s/logo.png', luajava.luaextdir, dirName)\n    local info = {\n        id = pluginId,\n        name = params.name,\n        icon = \"logo.png\",\n        main = \"main.lua\",\n        versionCode = 1,\n        versionName = \"1.0.0\",\n        desc = params.name .. \" - 氢页面\",\n    }\n    local code = luaTemp:gsub('{url}', params.url):gsub('{ssColor}', string.format(\"#%x\", params.themeColor))\n\n    write(infoPath, JSON.encode(info))\n    write(luaPath, code)\n\n    drawLogo(params.name, logoPath, params.themeColor)\n\n    activity.toast('打包成功，到主界面看一下吧！')\nend\n\n-- create view table\n\nlocal function editText(id, hint, inputType)\n    local t = {\n        EditText,\n        id = id,\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        textColor = \"#444444\",\n        hintTextColor = \"#AAAAAA\",\n        textSize = \"13sp\",\n        hint = hint,\n        singleLine = true,\n        layout_marginBottom = \"12dp\",\n    }\n    if inputType then t.inputType = inputType end\n\n    return t\nend\n\nlocal layout = {\n    FrameLayout,\n    layout_width = \"match\",\n    layout_height = \"match\",\n    background = \"#f1f1f1\",\n    {\n        ImageView,\n        id = 'iv_bg',\n        layout_width = \"match\",\n        layout_height = \"360dp\",\n    },\n    {\n        LinearLayout,\n        layout_width = \"match\",\n        gravity = \"center_horizontal\",\n        orientation = \"vertical\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"16dp\",\n        {\n            TextView,\n            layout_marginTop = \"40dp\",\n            text = \"打包网页\",\n            textColor = \"#ffffff\",\n            textSize = \"20sp\",\n        },\n        {\n            TextView,\n            id = 'tv_left',\n            layout_marginTop = \"40dp\",\n            textColor = \"#fafafa\",\n            text = '        该插件可以将网页应用转化成氢应用的插件，这样就可把一些做的比较好的网站或在线H5小游戏直接加入氢应用了，给你轻而纯粹的应用体验。',\n            lineSpacingMultiplier = 1.4,\n        },\n        {\n            FrameLayout,\n            layout_width = \"match\",\n            layout_marginTop = \"56dp\",\n            layout_marginLeft = \"16dp\",\n            layout_marginRight = \"16dp\",\n            {\n                LinearLayout,\n                layout_width = \"match\",\n                layout_marginBottom = \"32dp\",\n                background = \"#ffffff\",\n                orientation = \"vertical\",\n                paddingBottom = \"24dp\",\n                paddingLeft = \"16dp\",\n                paddingRight = \"16dp\",\n                paddingTop = \"16dp\",\n                editText('et_url', '网址 http(s)://', 11),\n                editText('et_name', '插件名称'),\n                editText('et_themeColor', '主题色（如 #3273EC 选填）'),\n                {\n                    Button,\n                    id = \"bt_test\",\n                    layout_width = \"fill\",\n                    layout_marginTop = \"24dp\",\n                    layout_marginBottom = \"48dp\",\n                    textSize = \"13sp\",\n                    text = \"戳我预览\",\n                    background = \"#eeeeee\",\n                    textColor = \"#444444\",\n                }\n            },\n            {\n                FloatingActionButton,\n                id = \"fab\",\n                layout_width = \"48dp\",\n                layout_height = \"48dp\",\n                layout_gravity = 81,\n                layout_marginBottom = \"12dp\",\n                src = '#packwap/check.png',\n                elevation = \"2dp\",\n            },\n        },\n    },\n}\n\nlocal function getParams()\n    local url = et_url.getText().toString()\n    local name = et_name.getText().toString()\n    local c = et_themeColor.getText().toString()\n    if c ~= '' and (not c:find(\"^#\")) then\n        c = '#' .. c\n        et_themeColor.setText(c)\n    end\n\n    local color = string.match(c, '#([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])')\n    if color == nil then\n        color = 0x33000000\n    else\n        color = tonumber('0xff' .. color)\n    end\n    return { url = url, name = name, themeColor = color }\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x00000000)\n    activity.setContentView(loadlayout(layout))\n\n    if Build.VERSION.SDK_INT < 16 then\n        iv_bg.setBackgroundDrawable(gd)\n    else\n        iv_bg.setBackground(gd)\n    end\n\n    bt_test.onClick = function()\n        local params = getParams()\n        if params.url == '' then\n            activity.toast('URL和名字不能为空')\n            return\n        end\n        if not params.url:find(\"^http\") then\n            params.url = 'http://' .. params.url\n            et_url.setText(params.url)\n        end\n\n\n        local intent = Intent(activity, LuaActivity)\n        intent.putExtra(\"luaPath\", 'packwap/testwap.lua')\n        intent.putExtra(\"url\", params.url)\n        intent.putExtra(\"params\", JSON.encode(params))\n        activity.startActivity(intent)\n    end\n\n    fab.onClick = function()\n        local params = getParams()\n        if params.url == '' or params.name == '' then activity.toast('URL和名字不能为空') return end\n        pack(params)\n    end\nend\n"
  },
  {
    "path": "lua/packwap/testwap.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- qiqu\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaWebView\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    statusBarColor = \"#33000000\",\n    {\n        LuaWebView,\n        id = \"webview\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    }\n}\n\nfunction onCreate(savedInstanceState)\n    local s  = activity.getIntent().getStringExtra(\"params\")\n    local params = JSON.decode(s)\n    if params.url == nil then\n        params.url = \"https://www.coolapk.com/apk/pub.hydrogen.android\"\n    end\n    layout.statusBarColor = string.format(\"#%x\",params.themeColor)\n    activity.setContentView(loadlayout(layout))\n    webview.loadUrl(params.url )\nend\n\nfunction onBackPressed()\n    if webview.canGoBack() then webview.goBack() return true end\n    return false\nend\n\nfunction onDestroy()\n    pcall(function( )\n        webview.release()\n    end)\nend\n"
  },
  {
    "path": "lua/papapatimer/info.json",
    "content": "{\n  \"id\": \"pub.hanks.papapatimer\",\n  \"name\": \"啪啪倒计时\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088a4ee4ca73c?w=150&h=150&f=png&s=2582\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0\",\n  \"versionCode\": 2,\n  \"desc\": \"小工具，计算相处多少天后啪啪啪\"\n}\n"
  },
  {
    "path": "lua/papapatimer/main.lua",
    "content": "require \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v7.widget.AppCompatSeekBar\"\nimport \"android.support.design.widget.FloatingActionButton\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.os.Build\"\nimport \"android.animation.ValueAnimator\"\nlocal Orientation = import \"android.graphics.drawable.GradientDrawable$Orientation\"\n\nlocal colors = luajava.createArray(\"int\", { 0xFF72A3FF, 0xFF607dff })\nlocal gd = GradientDrawable(Orientation.TOP_BOTTOM, colors)\n\nlocal function text(text)\n    return {\n        TextView,\n        layout_marginLeft = '16dp',\n        layout_marginTop = '12dp',\n        layout_marginBottom = '4dp',\n        text = text,\n        textColor = '#AAAAAA',\n        textSize = \"10sp\",\n    }\nend\n\nlocal function seekBar(id_sb, max, progress, id_tv, text)\n    return {\n        LinearLayout,\n        gravity = 'center_vertical',\n        layout_width = 'match',\n        paddingLeft = '2dp',\n        {\n            AppCompatSeekBar,\n            layout_weight = 1,\n            id = id_sb,\n            max = max,\n            progress = progress,\n        },\n        {\n            TextView,\n            layout_width = '20dp',\n            id = id_tv,\n            gravity = 'right',\n            textSize = '10sp',\n            text = text,\n        },\n    }\nend\n\nlocal layout = {\n    FrameLayout,\n    layout_width = \"match\",\n    layout_height = \"match\",\n    background = \"#f1f1f1\",\n    {\n        ImageView,\n        id = 'iv_bg',\n        layout_width = \"match\",\n        layout_height = \"360dp\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"match\",\n        layout_gravity = \"bottom\",\n        layout_marginBottom = \"24dp\",\n        layout_marginLeft = \"16dp\",\n        layout_marginRight = \"16dp\",\n        {\n            LinearLayout,\n            layout_width = \"match\",\n            layout_marginBottom = \"32dp\",\n            background = \"#ffffff\",\n            orientation = \"vertical\",\n            paddingBottom = \"24dp\",\n            paddingLeft = \"16dp\",\n            paddingRight = \"16dp\",\n            paddingTop = \"16dp\",\n            text('女方年龄 （40岁以上女性本公式不适用）'),\n            seekBar('seek_af', 40, 20, 'tv_af', '20'),\n            text('女方外貌 （10为满分）'),\n            seekBar('seek_lf', 10, 5, 'tv_lf', '5'),\n            text('男方外貌 （10为满分）'),\n            seekBar('seek_lm', 10, 5, 'tv_lm', '5'),\n            text('男方资产（价值），每10万港元为1个单位，无上限'),\n            {\n                LinearLayout,\n                gravity = 'center_vertical',\n                layout_width = 'match',\n                paddingLeft = '2dp',\n                {\n                    AppCompatSeekBar,\n                    layout_weight = 1,\n                    id = 'seek_wm',\n                    max = 100,\n                    progress = 0,\n                },\n                {\n                    EditText,\n                    inputType = 'number',\n                    background = '#00FFFFFF',\n                    layout_width = '20dp',\n                    id = 'tv_wm',\n                    gravity = 'right',\n                    textSize = '10sp',\n                    text = '0',\n                },\n            },\n            text('女方曾有性行为的男性数目（性伴侣）'),\n            seekBar('seek_sf', 15, 0, 'tv_sf', '0'),\n            {\n                View,\n                layout_height = '16dp',\n            },\n        },\n        {\n            FloatingActionButton,\n            id = \"fab\",\n            layout_width = \"48dp\",\n            layout_height = \"48dp\",\n            layout_gravity = 81,\n            layout_marginBottom = \"12dp\",\n            src = '#papapatimer/check.png',\n            elevation = \"2dp\",\n        },\n    },\n    {\n        LinearLayout,\n        layout_width = \"match\",\n        layout_height = \"match\",\n        gravity = \"center_horizontal\",\n        orientation = \"vertical\",\n        {\n            ImageView,\n            layout_width = '120dp',\n            layout_height = '16dp',\n            layout_marginTop = \"34dp\",\n            src = '#papapatimer/title.png',\n        },\n        {\n            LinearLayout,\n            layout_marginTop = '24dp',\n            gravity = \"bottom\",\n            {\n                TextView,\n                id = 'tv_left',\n                textColor = \"#fafafa\",\n                text = '交往',\n                textSize = \"10sp\",\n            },\n            {\n                TextView,\n                id = \"tv_result\",\n                layout_marginLeft = \"8dp\",\n                layout_marginRight = \"8dp\",\n                textColor = \"#ffffff\",\n                textSize = \"36sp\",\n                text = '999',\n            },\n            {\n                TextView,\n                id = 'tv_right',\n                text = '天后',\n                textColor = \"#fafafa\",\n                textSize = \"10sp\",\n            },\n        },\n        {\n            LinearLayout,\n            layout_marginTop = '12dp',\n            gravity = \"center_vertical\",\n            {\n                ImageView,\n                layout_width = '12dp',\n                layout_height = '12dp',\n                src = '#papapatimer/me.png',\n            },\n            {\n                ImageView,\n                id = 'iv_line',\n                layout_width = '100dp',\n                layout_height = '36dp',\n                layout_margin = '12dp',\n                src = '#papapatimer/line.png',\n            },\n            {\n                ImageView,\n                layout_width = '12dp',\n                layout_height = '12dp',\n                src = '#papapatimer/fe.png',\n            },\n        },\n    },\n}\n\nlocal function bindSeekText(sb_id, tv_id)\n    sb_id.setOnSeekBarChangeListener(luajava.createProxy('android.widget.SeekBar$OnSeekBarChangeListener', {\n        onProgressChanged = function(sb, progress, fromUser)\n            tv_id.setText(string.format('%d', progress))\n        end\n    }))\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x00000000)\n    activity.setContentView(loadlayout(layout))\n    bindSeekText(seek_af, tv_af)\n    bindSeekText(seek_lf, tv_lf)\n    bindSeekText(seek_lm, tv_lm)\n    bindSeekText(seek_wm, tv_wm)\n    bindSeekText(seek_sf, tv_sf)\n    if Build.VERSION.SDK_INT < 16 then\n        iv_bg.setBackgroundDrawable(gd)\n    else\n        iv_bg.setBackground(gd)\n    end\n\n\n    fab.onClick = function(view)\n        local v_af = seek_af.getProgress()\n        local v_lm = seek_lm.getProgress()\n        local v_lf = seek_lf.getProgress()\n        local v_sf = seek_sf.getProgress()\n        local v_wm = tonumber(tv_wm.getText().toString())\n        local res = ((40 - v_af) * (40 - v_af) + v_lf * v_lf * v_lf) * 10 / ((v_lm * v_lm + v_wm) * (v_sf + 1) * (v_sf + 1));\n        local text = string.format('%.2f', res)\n        if text:find('.') then\n            text = text:gsub('0+$', '')\n            if text:find('[.]$') then\n                text = text:sub(1, #text - 1)\n            end\n        end\n        if text == 'inf' then\n            text = '洗洗睡吧'\n            tv_left.setVisibility(8)\n            tv_right.setVisibility(8)\n        else\n            tv_left.setVisibility(0)\n            tv_right.setVisibility(0)\n        end\n        tv_result.setText(text)\n\n        local arr = luajava.createArray('float', { 1, 1.1, 0.9, 1.1, 0.9, 1 })\n        local animator = ValueAnimator.ofFloat(arr).setDuration(500)\n        animator.addUpdateListener(luajava.createProxy('android.animation.ValueAnimator$AnimatorUpdateListener', {\n            onAnimationUpdate = function(animation)\n                local value = animation.getAnimatedValue();\n                if iv_line then\n                    iv_line.setScaleX(value)\n                    iv_line.setScaleY(value)\n                end\n            end\n        }))\n        animator.start();\n    end\n\n    local info = [[        一条在线计算拍拖几天可以啪啪啪公式，纯理论，只作参考，实战一定有误差，过可理论日子都没啪到请先自我检讨。\n    \n        可以作为自己交往妹子，什么时候提出啪啪啪作为依据，以免被拒绝好尴尬。。。\n]]\n    iv_line.onClick = function()\n        local DialogBuilder = import \"android.app.AlertDialog$Builder\"\n        DialogBuilder(activity).setMessage(info).show()\n    end\nend\n"
  },
  {
    "path": "lua/pengpai/activity_news_detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"android.net.Uri\"\nimport \"pub.hydrogen.android.R\"\nimport \"androlua.widget.webview.WebViewActivity\"\nlocal android_R = import \"android.R\"\nlocal uihelper = require \"uihelper\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#33000000\",\n    {\n        Toolbar,\n        background = '#ffffff',\n        id = 'toolbar',\n        layout_width = \"match\",\n        layout_height = \"56dp\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            LuaWebView,\n            id = \"webview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal css = [[\n    video{width:100%}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-webkit-text-size-adjust:100%}body{font-family:'Helvetica Neue',Helvetica,Arial,Sans-serif;background:#fff;padding-top:0;margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0}h1,h2,h3,h4,h5,h6{font-size:16px}abbr[title]{border-bottom:1px dotted}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:\\201C\\201D\\2018\\2019}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0;vertical-align:middle;color:transparent;font-size:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}table{border-collapse:collapse;border-spacing:0;overflow:hidden}a{text-decoration:none}blockquote{border-left:3px solid #d0e5f2;font-style:normal;display:block;vertical-align:baseline;font-size:100%;margin:.5em 0;padding:0 0 0 1em}ul,ol{padding-left:20px}.content{color:#444;line-height:1.6em;font-size:16px;margin:16px}.content img{max-width:100%;display:block;margin:30px auto}.content img+img{margin-top:15px}.content img[src*=\"zhihu.com/equation\"]{display:inline-block;margin:0 3px}.content a{color:#259}.content a:hover{text-decoration:underline}\n]]\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html>\n<head>\n    <title></title>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width; initial-scale=1; minimum-scale=1; maximum-scale=2\">\n    <meta content=\"width=device-width,user-scalable=no\" name=\"viewport\">\n    <style type=\"text/css\"> %s </style>\n</head>\n<body>\n<div class=\"content\"> %s </div>\n<script type=\"text/javascript\">\nfunction openImgActivity(a,b){var c=JSON.stringify({currentIndex:b,uris:a});var d=\"hydrogen://pub.hydrogen.android?action=open_img&data=\"+c;var e=document.createElement(\"iframe\");e.src=d;e.style.display=\"none\";document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},2000)}function init(){var a=document.querySelectorAll(\".content img\");for(var b=0;b<a.length;b++){a[b].addEventListener(\"click\",function(g){var e=g.target||g.srcElement;var c=[];var d=0;var h=document.querySelectorAll(\".content img\");for(var f=0;f<h.length;f++){c[f]=h[f].getAttribute(\"src\");if(e.getAttribute(\"src\").indexOf(c[f])!=-1){d=f}}openImgActivity(c,d)})}}init();\n</script>\n</body>\n</html>\n]]\n\n\n\nlocal function getData(url)\n    print(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local content = string.match(body, 'class=\"news_part%s+.-\">%s+(.-)<div class=\"news_part_all\"')\n        if content == nil then\n            WebViewActivity.start(activity, url, 0xFF000000)\n            activity.finish()\n            return\n        end\n        local data = string.format(htmlTemplate, css, content)\n        data = data:gsub('width=\"%d+\"%s+height=\"%d+\"', '')\n        local title = string.match(body, '<h1 class=\"t_newsinfo\">(.-)</h1>')\n        uihelper.runOnUiThread(activity, function()\n            webview.loadData(data, \"text/html; charset=UTF-8\", nil)\n            activity.setTitle(title)\n        end)\n    end)\nend\n\nlocal url\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    activity.setSupportActionBar(toolbar)\n    activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true)\n    activity.getSupportActionBar().setDisplayShowHomeEnabled(true)\n    activity.setTitle('加载中...')\n    url = activity.getIntent().getStringExtra('url')\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    getData(url)\nend\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend\n\n\nfunction onCreateOptionsMenu(menu)\n    menu.add(\"浏览器打开\")\n    return true\nend\n\nfunction onOptionsItemSelected(item)\n    if item.getItemId() == android_R.id.home then\n        activity.onBackPressed()\n        return\n    end\n\n    local title = item.getTitle()\n    if title == \"浏览器打开\" then\n        activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))\n    end\n\nend\n\n\n"
  },
  {
    "path": "lua/pengpai/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\n\n\nlocal function getData(params, data, adapter, fragment, swipe_layout, reload)\n\n    local url = string.format('http://www.thepaper.cn/load_chosen.jsp?nodeids=%s&topCids=1772933,1773313,1773404,1773624,1773571,&pageidx=%d&lastTime=%d', params.rid, params.page, os.time() * 1000)\n    print(url)\n\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then return end\n        local arr = {}\n       \n        for img, url, title, p, source, ptime in string.gmatch(body, 'class=\"tiptitleImg\".-<img src=\"(.-)\".-<h2>%s+<a href=\"(.-)\".->(.-)</a>%s+</h2>.-<p>(.-)</p>%s+<div class=\"pdtt_trbs\">.-<a.->(.-)</a>.-<span>(.-)</span>') do\n            local item = {\n                img = 'http:'.. img,\n                title = title,\n                p = p,\n                ptime = ptime,\n                source = source,\n                url = url\n            }\n            print(item)\n            arr[#arr + 1] = item\n        end\n\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                for k, _ in pairs(date) do data[k] = nil end\n            end\n            for i = 1, #arr do\n                data[#data + 1] = arr[i]\n            end\n            params.page = params.page + 1\n            adapter.notifyDataSetChanged()\n            swipe_layout.setRefreshing(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, item)\n    local activity = fragment.getActivity()\n    if item == nil or item.url == nil then\n        activity.toast('没有 url 可以打开')\n        return\n    end\n    local url = item.url\n    if not item.url:find('^http://') then\n        url = 'http://m.thepaper.cn/' .. item.url\n    end\n    local activity = fragment.getActivity()\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'pengpai/activity_news_detail.lua')\n    intent.putExtra(\"url\", url)\n    activity.startActivity(intent)\nend\n\n\nlocal function newInstance(rid)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            ListView,\n            id = \"listview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        RelativeLayout,\n        layout_width = \"fill\",\n        layout_height = \"wrap\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"12dp\",\n        paddingTop = \"16dp\",\n        paddingBottom = \"16dp\",\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_width = \"110dp\",\n            layout_height = \"83dp\",\n            layout_marginRight = \"12dp\",\n            scaleType = \"centerCrop\",\n        },\n        {\n            TextView,\n            id = \"tv_title\",\n            layout_toRightOf = \"iv_image\",\n            layout_width = \"fill\",\n            maxLines = \"2\",\n            lineSpacingMultiplier = 1.3,\n            textSize = \"16sp\",\n            textColor = \"#222222\",\n        },\n        {\n            TextView,\n            id = \"tv_date\",\n            layout_toRightOf = \"iv_image\",\n            layout_alignParentBottom = true,\n            layout_width = \"fill\",\n            textSize = \"12sp\",\n            textColor = \"#aaaaaa\",\n        }\n    }\n    local singleImg = {\n        ImageView,\n        layout_width = (uihelper.getScreenWidth() - uihelper.dp2px(44)) / 3,\n        layout_height = \"83dp\",\n        layout_marginRight = \"8dp\",\n        scaleType = \"centerCrop\",\n    }\n\n    local hadLoadData\n    local isVisible\n    local lastId\n    local params = { rid = rid, page = 0 }\n    local data = {}\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(params, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        convertView.getLayoutParams().width = parent.getWidth()\n                        convertView.setTag(views)\n                    end\n                    local views = convertView.getTag()\n                    local item = data[position]\n                    if item then\n\n                        views.iv_image.setVisibility(0)\n                        LuaImageLoader.load(views.iv_image, item.img)\n                        views.tv_date.setText(string.format('%s        %s', item.ptime, item.source))\n                        views.tv_title.setText(item.title)\n                    end\n\n                    if position == #data then getData(params, data, adapter, fragment, ids.swipe_layout) end\n\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    launchDetail(fragment, data[position + 1])\n                end,\n            }))\n            ids.swipe_layout.setRefreshing(true)\n            ids.swipe_layout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    getData(params, data, adapter, fragment, ids.swipe_layout, true)\n                end\n            }))\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/pengpai/info.json",
    "content": "{\n  \"id\": \"pub.hanks.pengpainews\",\n  \"name\": \"澎湃新闻\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b0889e8328d952?w=150&h=150&f=png&s=6544\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.6\",\n  \"versionCode\": 7,\n  \"desc\": \"澎湃新闻客户端\"\n}\n"
  },
  {
    "path": "lua/pengpai/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"android.net.Uri\"\n\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal fragmentNews = require \"pengpai/fragment_news\"\n\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#33000000\",\n    {\n        Toolbar,\n        background = '#ffffff',\n        id = 'toolbar',\n        layout_width = \"match\",\n        layout_height = \"56dp\",\n        {\n            ImageView,\n            layout_width = \"54dp\",\n            layout_height = \"32dp\",\n            scaleType = \"fitXY\",\n            src = \"#pengpai/logo.png\"\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\n\ntable.insert(data.fragments, fragmentNews.newInstance('25949'))\ntable.insert(data.titles, '精选')\n\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    activity.setSupportActionBar(toolbar)\n    activity.setTitle('')\n    viewPager.setAdapter(adapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\nend\n\nfunction onCreateOptionsMenu(menu)\n    menu.add(\"网页版\")\n    return true\nend\n\nfunction onOptionsItemSelected(item)\n    local title = item.getTitle()\n    if title == \"网页版\" then\n        activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse('http://m.thepaper.cn')))\n    end\nend\n"
  },
  {
    "path": "lua/pixiv/info.json",
    "content": "{\n  \"id\": \"pub.hanks.pixiv\",\n  \"name\": \"P站排行\",\n  \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fh803sp03xj2046046a9x.jpg\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 2,\n  \"private\": true,\n  \"desc\": \"P站每日插画排行\"\n}\n"
  },
  {
    "path": "lua/pixiv/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.StaggeredGridLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\n\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\nlocal date = os.date(\"%Y%m%d\", os.time() - 60 * 60 * 24) -- 20170518\nlocal page = 1\nlocal data = {}\nlocal adapter\nlocal imageWidth = uihelper.getScreenWidth() / 2\n\n-- create view table\nlocal layout = {\n    RecyclerView,\n    id = \"recyclerView\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    {\n        ImageView,\n        id = \"iv_image\",\n        layout_width = \"fill\",\n        layout_height = \"200dp\",\n        scaleType = \"fitXY\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_gravity = \"right\",\n        background = \"#88000000\",\n        paddingLeft = \"6dp\",\n        paddingRight = \"6dp\",\n        paddingTop = \"2dp\",\n        paddingBottom = \"2dp\",\n        textSize = \"10sp\",\n        textColor = \"#aaffffff\",\n    },\n    {\n        View,\n        id = \"layer\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        background = \"@drawable/layout_selector_tran\",\n        clickable = true,\n    },\n}\n\nlocal function offsetDate()\n    local y = date:sub(1, 4)\n    local m = date:sub(5, 6)\n    local d = date:sub(7, 8)\n    date = os.date(\"%Y%m%d\", os.time({ year = y, month = m, day = d, hour = 1, min = 1, sec = 1 }) - 60 * 60 * 24)\n    page = 1\nend\n\nlocal function fetchData()\n    local url = string.format('http://www.pixiv.net/ranking.php?mode=daily&content=illust&p=%s&format=json&date=%s', page, date)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then\n            offsetDate()\n            fetchData()\n            return\n        end\n        local json = JSON.decode(body)\n        if json.error then\n            offsetDate()\n            fetchData()\n            return\n        end\n        if json.next == nil or json.next == false then\n            page = 1\n            date = json.prev_date\n        else\n            page = json.next\n        end\n        local arr = json.contents\n        uihelper.runOnUiThread(activity, function()\n            local s = #data\n            for i = 1, #arr do\n                local item = arr[i]\n                item.calcHeight = math.floor(imageWidth * item.height / item.width)\n                data[#data + 1] = item\n            end\n            adapter.notifyItemRangeChanged(s, #data)\n        end)\n    end)\nend\n\nlocal function launchDetail(item)\n    local args = { uris = {}, headers = { \"referer:https://pximg.net\" } }\n    local original = item.url:gsub('/c/240x480', '')\n    local count = tonumber(item.illust_page_count)\n    if count then\n        for i = 1, count do\n            local l, r = original:find('_p(%d+).-jpg$')\n            if l and r then\n                local rr = original:sub(l, r):gsub('_p(%d+)', '_p' .. i - 1)\n                args.uris[#args.uris + 1] = original:sub(1, l - 1) .. rr\n            end\n        end\n    end\n    PicturePreviewActivity.start(activity, JSON.encode(args))\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.getLayoutParams().width = imageWidth\n            holder.itemView.setTag(views)\n            views.layer.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1\n                launchDetail(data[position])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local item = data[position]\n            local views = holder.itemView.getTag()\n            views.iv_image.getLayoutParams().height = item.calcHeight\n            if tonumber(item.illust_page_count) == 1 then\n                views.tv_title.setVisibility(8)\n            else\n                views.tv_title.setVisibility(0)\n                views.tv_title.setText(item.illust_page_count .. 'P')\n            end\n            LuaImageLoader.load(views.iv_image, item.url)\n            if position == #data then fetchData() end\n        end,\n    }))\n    recyclerView.setLayoutManager(StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL))\n    recyclerView.setAdapter(adapter)\n    fetchData()\nend\n"
  },
  {
    "path": "lua/proxy_fetch/info.json",
    "content": "{\n    \"id\": \"pub.hanks.proxy_fetch\",\n    \"private\": true,\n    \"name\": \"抓取代理\",\n    \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fhmrw8qtpej2046046t8h.jpg\",\n    \"main\": \"main.lua\",\n    \"versionName\": \"1.0.0\",\n    \"versionCode\": 1,\n    \"desc\": \"抓取代理\"\n  }"
  },
  {
    "path": "lua/proxy_fetch/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.StaggeredGridLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"android.support.v4.app.ActivityCompat\"\nimport \"android.Manifest\"\n\nlocal filehelper = require(\"filehelper\")\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\nlocal page = 1\nlocal data = {}\nlocal adapter\nlocal imageWidth = uihelper.getScreenWidth() / 2\n\nlocal filePath = '/sdcard/ip_pool.json'\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        TextView,\n        id = \"tv_go\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        layout_margin = \"40dp\",\n        background = \"#88000000\",\n        gravity = \"center\",\n        textSize = \"14sp\",\n        text = \"开始\",\n        textColor = \"#aaffffff\",\n    },\n    {\n        ScrollView,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            TextView,\n            id = \"tv_result\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n            textSize = \"10sp\",\n            textColor = \"#414141\",\n        },\n    }\n    \n}\n  \nlocal function fetchData()\n    local date = os.time() * 1000\n    local url = string.format('http://47.97.7.119:8080/proxypool/proxyController/queryProxy?page=1&rows=150&sort=proxyAddress&order=desc&_=%d', date)\n    print(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then\n            uihelper.runOnUiThread(activity, function()\n                tv_result.setText('失败:' .. code)\n            end)\n            return\n        end\n        local json = JSON.decode(body)\n        local arr = json.rows\n        uihelper.runOnUiThread(activity, function()\n            for i = 1, #arr do\n                local item = arr[i]\n                data[#data + 1] = {\n                    ip = item.proxyAddress,\n                    port = item.proxyPort,\n                    type = item.proxyType\n                }\n            end\n            local result = JSON.encode(data)\n            tv_result.setText(result)\n            filehelper.writefile(filePath, result)\n        end)\n    end)\nend\n \n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    tv_go.onClick = function()\n        fetchData()\n    end\n    ActivityCompat.requestPermissions(activity,\n                {Manifest.permission.WRITE_EXTERNAL_STORAGE},\n                0x23);\nend\n"
  },
  {
    "path": "lua/proxy_fetch_mogu/info.json",
    "content": "{\n    \"id\": \"pub.hanks.proxy_fetch_mogu\",\n    \"private\": true,\n    \"name\": \"蘑菇代理\",\n    \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fhmrw8qtpej2046046t8h.jpg\",\n    \"main\": \"main.lua\",\n    \"versionName\": \"1.0.0\",\n    \"versionCode\": 1,\n    \"desc\": \"抓取代理\"\n  }"
  },
  {
    "path": "lua/proxy_fetch_mogu/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.StaggeredGridLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"android.support.v4.app.ActivityCompat\"\nimport \"android.Manifest\"\n\nlocal filehelper = require(\"filehelper\")\nlocal JSON = require(\"cjson\")\nlocal uihelper = require('uihelper')\nlocal page = 1\nlocal data = {}\nlocal adapter\nlocal imageWidth = uihelper.getScreenWidth() / 2\n\nlocal filePath = '/sdcard/ip_pool.json'\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        TextView,\n        id = \"tv_go\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        layout_margin = \"40dp\",\n        background = \"#88000000\",\n        gravity = \"center\",\n        textSize = \"14sp\",\n        text = \"开始\",\n        textColor = \"#aaffffff\",\n    },\n    {\n        ScrollView,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            TextView,\n            id = \"tv_result\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n            textSize = \"10sp\",\n            textColor = \"#414141\",\n        },\n    }\n    \n}\n  \nlocal function fetchData()\n    local date = os.time() * 1000\n    local url = string.format('http://www.mogumiao.com/proxy/free/listFreeIp')\n    print(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then\n            uihelper.runOnUiThread(activity, function()\n                tv_result.setText('失败:' .. code)\n            end)\n            return\n        end\n        local json = JSON.decode(body)\n        local arr = json.msg\n        uihelper.runOnUiThread(activity, function()\n            for i = 1, #arr do\n                local item = arr[i]\n                data[#data + 1] = {\n                    ip = item.ip,\n                    port = item.port,\n                    type = \"mogu\",\n                }\n            end\n            local result = JSON.encode(data)\n            tv_result.setText(result)\n            filehelper.writefile(filePath, result)\n        end)\n    end)\nend\n \n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x33000000)\n    activity.setContentView(loadlayout(layout))\n    tv_go.onClick = function()\n        fetchData()\n    end\n    ActivityCompat.requestPermissions(activity,\n                {Manifest.permission.WRITE_EXTERNAL_STORAGE},\n                0x23);\nend\n"
  },
  {
    "path": "lua/qiqu/info.json",
    "content": "{\n  \"id\": \"pub.hanks.qiqu\",\n  \"name\": \"奇趣百科\",\n  \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fh10pf0gqkj2046046748.jpg\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0\",\n  \"versionCode\": 1,\n  \"private\": true,\n  \"desc\": \"提取自奇趣百科，优化浏览体验\"\n}\n"
  },
  {
    "path": "lua/qiqu/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- qiqu\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaWebView\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    statusBarColor = \"#F79100\",\n    {\n        TextView,\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#F79100\",\n        gravity = \"center\",\n        text = \"奇趣百科\",\n        textColor = \"#FFFFFF\",\n        textSize = \"18sp\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            LuaWebView,\n            id = \"webview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n    }\n}\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    webview.loadUrl('http://hanks.pub/joke/')\nend\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend\n"
  },
  {
    "path": "lua/qqtools/info.json",
    "content": "{\n  \"id\": \"pub.hanks.qqtools\",\n  \"name\": \"QQ 工具箱\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088883254f7d4?w=150&h=150&f=png&s=3988\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.2\",\n  \"versionCode\": 4,\n  \"desc\": \"QQ 工具箱\"\n}\n"
  },
  {
    "path": "lua/qqtools/main.lua",
    "content": "require \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.net.Uri\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"android.support.v7.widget.AppCompatSeekBar\"\nimport \"android.view.inputmethod.InputMethodManager\"\nlocal DialogBuilder = import \"android.app.AlertDialog$Builder\"\nlocal uihelper = require \"uihelper\"\n-- create view table\nlocal itemHeight = uihelper.getScreenWidth() * 0.16\nlocal itemWidth = uihelper.getScreenWidth() * 0.5\nlocal function doubleButton(leftId, leftText, rightId, rightText)\n    return {\n        LinearLayout,\n        layout_width = \"fill\",\n        {\n            FrameLayout,\n            layout_width = itemWidth,\n            layout_height = itemHeight,\n            padding = '8dp',\n            {\n                ImageView,\n                layout_width = \"match\",\n                layout_height = \"match\",\n                scaleType = \"centerCrop\",\n                src = 'http://ww1.sinaimg.cn/large/8c9b876fly1fic6hr2qe9j20ch05mq3q.jpg',\n            },\n            {\n                TextView,\n                layout_width = \"match\",\n                layout_height = \"match\",\n                background = '@drawable/layout_selector_tran',\n                id = leftId,\n                gravity = 'center',\n                textColor = '#ffffff',\n                text = leftText,\n            }\n        },\n        {\n            FrameLayout,\n            layout_width = itemWidth,\n            layout_height = itemHeight,\n            padding = '8dp',\n            {\n                ImageView,\n                scaleType = \"centerCrop\",\n                layout_width = \"match\",\n                layout_height = \"match\",\n                src = 'http://ww1.sinaimg.cn/large/8c9b876fly1fic6i5up5yj20ct0580w6.jpg',\n            },\n            {\n                TextView,\n                background = '@drawable/layout_selector_tran',\n                layout_width = \"match\",\n                layout_height = \"match\",\n                id = rightId,\n                gravity = 'center',\n                textColor = '#ffffff',\n                text = rightText,\n            }\n        },\n    }\nend\n\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    statusBarColor = '#12B7F5',\n    {\n        Toolbar,\n        background = '#12B7F5',\n        id = 'toolbar',\n        titleTextColor = '#FFFFFF',\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n    },\n    {\n        LinearLayout,\n        orientation = \"vertical\",\n        padding = \"8dp\",\n        layout_width = \"fill\",\n        doubleButton('qq_chat', 'QQ 强制会话', 'qq_hide_card', 'QQ 隐藏名片'),\n        doubleButton('qq_dashang', 'QQ 说说打赏', 'qq_blue_ss', 'QQ 蓝字说说'),\n        doubleButton('qq_shuaping', 'QQ 无限刷屏', 'qq_kasi', 'QQ 聊天卡死'),\n    },\n}\n\nlocal layout_intput = {\n    RelativeLayout,\n    layout_width = 'wrap',\n    paddingBottom = '8dp',\n    paddingRight = '8dp',\n    {\n        EditText,\n        id = 'et',\n        layout_margin = '16dp',\n        layout_width = 'match',\n    },\n    {\n        Button,\n        id = 'tv_ok',\n        layout_below = 'et',\n        background = '@drawable/layout_selector_tran',\n        layout_alignParentRight = true,\n        text = '确定',\n    },\n    {\n        Button,\n        id = 'tv_cancel',\n        layout_below = 'et',\n        background = '@drawable/layout_selector_tran',\n        layout_toLeftOf = 'tv_ok',\n        text = '取消',\n    },\n}\n\nlocal function showDialog(title, hint, leftText, rightText, inputType, callback)\n    local ids = {}\n    local view = loadlayout(layout_intput, ids, ViewGroup)\n    local dialog = DialogBuilder(activity).setTitle(title).setView(view).create()\n    dialog.show()\n    ids.et.setHint(hint or '')\n    ids.et.setInputType(inputType or 0x00000001)\n    ids.tv_cancel.setText(leftText or '取消')\n    ids.tv_ok.setText(rightText or '确定')\n    ids.tv_ok.onClick = function()\n        dialog.dismiss()\n        local text = ids.et.getText().toString()\n        callback(text)\n    end\n    ids.tv_cancel.onClick = function()\n        dialog.dismiss()\n    end\n    ids.et.postDelayed(luajava.createProxy('java.lang.Runnable', {\n        run = function()\n            activity.getSystemService(Context.INPUT_METHOD_SERVICE).toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS)\n        end\n    }), 300)\nend\n\nlocal function copyText(text)\n    local clipboard = activity.getSystemService(Context.CLIPBOARD_SERVICE)\n    local clip = ClipData.newPlainText(\"氢应用\", text)\n    clipboard.setPrimaryClip(clip)\n    activity.toast('已复制到剪切板')\nend\n\nlocal function installed(package)\n    return pcall(function()\n        activity.getPackageManager().getPackageInfo(package,0)\n    end) \nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0xff12B7F5)\n    activity.setContentView(loadlayout(layout))\n    activity.setSupportActionBar(toolbar)\n    activity.setTitle('QQ 工具箱')\n    toolbar.setNavigationIcon(LuaDrawable.create('qqtools/qq.png'))\n    qq_chat.onClick = function()\n        showDialog('QQ 强制会话', '对方 qq 号', '放弃', '会话', 0x00000002, function(text)\n            local url = \"mqqwpa://im/chat?chat_type=wpa&uin=\" .. text\n            local intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))\n            if (intent.resolveActivity(activity.getPackageManager())) then\n                activity.startActivity(intent)\n            else\n                activity.toast('找不到 QQ 客户端')\n            end\n        end)\n    end\n\n    qq_dashang.onClick = function()\n        showDialog('QQ 说说打赏', '打赏金额', '放弃', '生成并复制', 0x00000002, function(text)\n            copyText(\"[em]e10033[/em]{uin:2742,nick: 打赏了\" .. text .. \"元红包}\")\n        end)\n    end\n\n    qq_blue_ss.onClick = function()\n        showDialog('QQ 蓝字说说', '输入说说内容', nil, '生成并复制', nil, function(text)\n            copyText(\"{uin:0,nick:\" .. text .. \",who:1}\")\n        end)\n    end\n\n    qq_hide_card.onClick = function()\n        showDialog('QQ 隐藏名片', '输入你的名片', nil, '生成并复制', nil, function(text)\n            local t = {}\n            for i = 1, #text - 1 do\n                t[i] = text:sub(i, i + 1)\n            end\n            copyText(\"\\020\" .. table.concat(t, \"\\020\") .. \"\\020\")\n        end)\n    end\n\n    qq_shuaping.onClick = function()\n        local ids = {}\n        local layout = {\n            LinearLayout,\n            layout_width = 'match',\n            padding = '12dp',\n            {\n                AppCompatSeekBar,\n                max = 100,\n                id = 'progress',\n                layout_weight = 1,\n            },\n            {\n                TextView,\n                id = 'tv_progress',\n                layout_width = '20dp',\n                textSize = '12sp',\n            }\n        }\n        local view = loadlayout(layout, ids, ViewGroup)\n        ids.progress.setOnSeekBarChangeListener(luajava.createProxy('android.widget.SeekBar$OnSeekBarChangeListener', {\n            onProgressChanged = function(seekBar, p, fromUser)\n                ids.tv_progress.setText(p .. '')\n            end\n        }))\n        ids.progress.setProgress(50)\n        DialogBuilder(activity).setTitle('设置刷屏强度').setView(view).setNegativeButton('取消', nil).setPositiveButton('确定', luajava.createProxy('android.content.DialogInterface$OnClickListener', {\n            onClick = function(dialog, which)\n                local p = ids.progress.getProgress()\n                local text = ''\n                for i = 1, p do text = text .. '\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n' end\n                local qqIntent = Intent(Intent.ACTION_SEND)\n                local package = \"com.tencent.mobileqq\"\n                if installed(\"com.tencent.tim\") then package = \"com.tencent.tim\" end\n                qqIntent.setClassName(package, \"com.tencent.mobileqq.activity.JumpActivity\")\n                qqIntent.setType(\"text/plain\")\n                qqIntent.putExtra(Intent.EXTRA_TEXT, text)\n                if qqIntent.resolveActivity(activity.getPackageManager()) then\n                        activity.startActivity(qqIntent)\n                else\n                    activity.toast('找不到 QQ 客户端')\n                end\n            end\n        })).show()\n    end\n    qq_kasi.onClick = function()\n        local ids = {}\n        local layout = {\n            LinearLayout,\n            layout_width = 'match',\n            padding = '12dp',\n            {\n                AppCompatSeekBar,\n                max = 15,\n                id = 'progress',\n                layout_weight = 1,\n            },\n            {\n                TextView,\n                id = 'tv_progress',\n                layout_width = '20dp',\n                textSize = '12sp',\n            }\n        }\n        local view = loadlayout(layout, ids, ViewGroup)\n        ids.progress.setOnSeekBarChangeListener(luajava.createProxy('android.widget.SeekBar$OnSeekBarChangeListener', {\n            onProgressChanged = function(seekBar, p, fromUser)\n                ids.tv_progress.setText(p .. '')\n            end\n        }))\n        ids.progress.setProgress(8)\n        DialogBuilder(activity).setTitle('设置卡死强度').setView(view).setNegativeButton('取消', nil).setPositiveButton('确定', luajava.createProxy('android.content.DialogInterface$OnClickListener', {\n            onClick = function(dialog, which)\n                local p = ids.progress.getProgress()\n                local text = ''\n                for i = 1, p do text = text .. \"\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\195\\186\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\n\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\195\\186\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\n\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\195\\186\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\n\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\195\\186\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\n\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\n\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\\020\\194\\170\" end\n                local qqIntent = Intent(Intent.ACTION_SEND)\n                local package = \"com.tencent.mobileqq\"\n                if installed(\"com.tencent.tim\") then package = \"com.tencent.tim\" end\n                qqIntent.setClassName(package, \"com.tencent.mobileqq.activity.JumpActivity\")\n                qqIntent.setType(\"text/plain\")\n                qqIntent.putExtra(Intent.EXTRA_TEXT, text)\n                if qqIntent.resolveActivity(activity.getPackageManager()) then\n                        activity.startActivity(qqIntent)\n                else\n                    activity.toast('找不到 QQ 客户端')\n                end\n            end\n        })).show()\n    end\nend\n\n"
  },
  {
    "path": "lua/quanmm/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.os.Build\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal floor = math.floor\nlocal tonum = tonumber\nlocal imageWidth = uihelper.getScreenWidth()\n\nlocal function getData(params, data, adapter, fragment, swipe_layout, reload)\n    local url =  string.format(params.url, params.page)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then return end\n        params.page = params.page + 1\n        local json = JSON.decode(body)\n        local arr = json.data.rows\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                for k, _ in ipairs(data) do data[k] = nil end\n            end\n            local s = #data\n            for i = 1, #arr do\n                local item = arr[i]\n                data[#data + 1] = item\n            end\n            adapter.notifyItemRangeChanged(s, #arr)\n            swipe_layout.setRefreshing(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, data, index)\n    local item = data[index+1]\n    WebViewActivity.start(activity, item.article_link, 0xFFFF6666)\nend\n\nlocal function newInstance(rid)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            RecyclerView,\n            id = \"recyclerView\",\n            background = '#ffffff',\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"104dp\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"16dp\",\n        background = '@drawable/layout_selector_tran',\n        { View, layout_width=\"fill\", layout_height=\"0.5dp\", background = \"#f0f0f0\"},\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_marginTop = \"16dp\",\n            layout_width = \"72dp\",\n            layout_height = \"72dp\",\n        },\n        {\n            TextView, \n            id = \"tv_title\",\n            layout_width = \"fill\",\n            layout_height = \"20dp\",\n            layout_marginTop = \"14dp\",\n            layout_marginLeft = \"92dp\",\n            textSize = \"15sp\",\n            textColor = \"#111111\",\n            maxLines = 1,\n        },\n        {\n            TextView, \n            id = \"tv_desc\",\n            layout_width = \"fill\",\n            layout_height = \"20dp\",\n            layout_marginLeft = \"92dp\",\n            layout_gravity = \"center_vertical\",\n            textColor = \"#FF4D4D\",\n            textSize = \"13sp\",\n            maxLines = 1,\n        },\n        {\n            TextView, \n            id = \"tv_from\",\n            layout_height = \"16dp\",\n            layout_gravity = \"bottom\",\n            textColor = \"#AEAEAE\",\n            layout_marginLeft = \"92dp\",\n            layout_marginBottom = \"16dp\",\n            textSize = \"12sp\",\n            maxLines = 1,\n        },\n        {\n            TextView, \n            layout_marginBottom = \"16dp\",\n            id = \"tv_viewcount\",\n            layout_gravity = 85,\n            textColor = \"#AEAEAE\",\n            layout_height = \"16dp\",\n            textSize = \"12sp\",\n            maxLines = 1,\n        },\n         \n    }\n\n\n    local hadLoadData\n    local isVisible\n    local lastId\n    local params = { url = rid, page = 1 }\n    local data = {}\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(params, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n                getItemCount = function() return #data end,\n                onCreateViewHolder = function(parent, viewType)\n                    local views = {}\n                    local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n                    holder.itemView.getLayoutParams().width = imageWidth\n                    holder.itemView.setTag(views)\n                    holder.itemView.onClick = function(view)\n                        local position = holder.getAdapterPosition()\n                        launchDetail(fragment, data, position)\n                    end\n                    return holder\n                end,\n                onBindViewHolder = function(holder, position)\n                    position = position + 1\n                    local item = data[position]\n                    local views = holder.itemView.getTag() \n                    LuaImageLoader.load(views.iv_image, item.article_thumbnail)\n                    views.tv_title.setText(item.article_title)\n                    views.tv_desc.setText(item.article_vicetitle)\n                    views.tv_from.setText(item.article_mall)\n                    views.tv_viewcount.setText(item.article_read_count_str)\n                    if position == #data then getData(params, data, adapter, fragment, ids.swipe_layout) end\n                end,\n            }))\n            ids.recyclerView.setLayoutManager(LinearLayoutManager(activity))\n            ids.recyclerView.setAdapter(adapter)\n            ids.swipe_layout.setRefreshing(true)\n            ids.swipe_layout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    getData(params, data, adapter, fragment, ids.swipe_layout, true)\n                end\n            }))\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/quanmm/info.json",
    "content": "{\n  \"id\": \"pub.hanks.quanmm\",\n  \"name\": \"券妈妈\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b08882ec273df8?w=150&h=150&f=png&s=2540\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 2,\n  \"desc\": \"领取各种优惠券\"\n}\n"
  },
  {
    "path": "lua/quanmm/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"pub.hydrogen.android.R\"\nimport \"android.net.Uri\"\nimport \"android.os.Build\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal fragmentNews = require \"quanmm/fragment_news\"\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    orientation = \"vertical\",\n    {\n        View,\n        id = \"statusBar\",\n        background = '#FFFF6666',\n        layout_width = \"fill\",\n    },\n    {\n        Toolbar,\n        background = '#FFFF6666',\n        id = 'toolbar',\n        layout_width = \"match\",\n        layout_height = \"48dp\",\n        titleTextColor = \"#88ffffff\",\n        {\n            TabLayout,\n            id = \"tab\",\n            layout_width = \"match\",\n            layout_height = \"match\",\n        },\n    }, \n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\ntable.insert(data.fragments, fragmentNews.newInstance('http://app.quanmama.com/apios/v5/appZdmList.ashx?f=android&test=0&code=503&platform=Tencent&v=5.0.3&phoneversion=22&pageindex=%d&adsysno=1006&trackSysNo=1006&pagetype=3&dplus_fenlei_name=最新&apphomerankindex=1&sort=1&pagesize=20'))\ntable.insert(data.titles, '最新')\n\ntable.insert(data.fragments, fragmentNews.newInstance('http://app.quanmama.com/apios/v5/appZdmList.ashx?f=android&test=0&code=503&platform=Tencent&v=5.0.3&phoneversion=22&pageindex=%d&adsysno=1004&trackSysNo=1004&pagetype=3&dplus_fenlei_name=最热&apphomerankindex=1&sort=1&pagesize=20'))\ntable.insert(data.titles, '最热')\n\ntable.insert(data.fragments, fragmentNews.newInstance('http://app.quanmama.com/apios/v5/appZdmList.ashx?f=android&test=0&code=503&platform=Tencent&v=5.0.3&phoneversion=22&pageindex=%d&category=5391&sort=1&trackSysNo=4030&pagesize=20'))\ntable.insert(data.titles, '外卖')\n\ntable.insert(data.fragments, fragmentNews.newInstance('http://app.quanmama.com/apios/v5/appZdmList.ashx?f=android&test=0&code=503&platform=Tencent&v=5.0.3&phoneversion=22&pageindex=%d&category=1257&sort=1&trackSysNo=4028&pagesize=20'))\ntable.insert(data.titles, '出行')\n\ntable.insert(data.fragments, fragmentNews.newInstance('http://app.quanmama.com/apios/v5/appZdmList.ashx?f=android&test=0&code=503&platform=Tencent&v=5.0.3&phoneversion=22&pageindex=%d&category=1187&sort=1&trackSysNo=4031&pagesize=20'))\ntable.insert(data.titles, '观影')\n\ntable.insert(data.fragments, fragmentNews.newInstance('http://app.quanmama.com/apios/v5/appZdmList.ashx?f=android&test=0&usertoken=&code=503&platform=Tencent&v=5.0.3&phoneversion=22&imei=867247020524723&channelrankindex=1&sort=1&trackSysNo=4032&storetype=-1&youhuitype=100101&pagesize=20&pageindex=%d'))\ntable.insert(data.titles, '网购')\n\ntable.insert(data.fragments, fragmentNews.newInstance('http://app.quanmama.com/apios/v5/appZdmList.ashx?f=android&test=0&usertoken=&code=503&platform=Tencent&v=5.0.3&phoneversion=22&imei=867247020524723&channelrankindex=1&sort=1&trackSysNo=4140&storetype=-1&youhuitype=100102&tagSysNo=26615&pagesize=20&pageindex=%d'))\ntable.insert(data.titles, '团购')\n\ntable.insert(data.fragments, fragmentNews.newInstance('http://app.quanmama.com/apios/v5/appZdmList.ashx?f=android&test=0&usertoken=&code=503&platform=Tencent&v=5.0.3&phoneversion=22&imei=867247020524723&channelrankindex=1&sort=1&trackSysNo=4051&storetype=-1&youhuitype=10010204&pagesize=20&pageindex=%d'))\ntable.insert(data.titles, '旅游酒店')\n\ntable.insert(data.fragments, fragmentNews.newInstance('http://app.quanmama.com/apios/v5/appZdmList.ashx?f=android&test=0&usertoken=&code=503&platform=Tencent&v=5.0.3&phoneversion=22&imei=867247020524723&channelrankindex=1&sort=1&trackSysNo=4053&storetype=-1&tagSysNo=90584&pagesize=20&pageindex=%d'))\ntable.insert(data.titles, '专享券')\n \n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    activity.setSupportActionBar(toolbar)\n    activity.setStatusBarColor(0x33000000)\n    activity.setTitle('')\n    toolbar.setNavigationIcon(LuaDrawable.create('quanmm/quan.png'))\n    toolbar.setNavigationOnClickListener(luajava.createProxy(\"android.view.View$OnClickListener\",{\n        onClick = function(v)\n           activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse('http://m.quanmama.com/mobile/home')))\n        end\n    }));\n    local h = 0\n    if Build.VERSION.SDK_INT >= 21 then h = uihelper.dp2px(25) end\n    statusBar.getLayoutParams().height = h\n\n    viewPager.setAdapter(adapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\n    tab.setSelectedTabIndicatorColor(0xeeffffff)\n    tab.setTabTextColors(0x88ffffff, 0xeeffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n\n"
  },
  {
    "path": "lua/readhub/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.os.Build\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\n\nlocal function dateStr(d)\n    if type(d) == 'string' then\n        local y,m,d,h,M,s = string.match(d,'(%d%d%d%d)[-](%d%d)[-](%d%d)T(%d%d):(%d%d):(%d%d).') \n        return dateStr(os.time({ year = y, month = m, day = d, hour = h+8, min = M, sec=s}))\n    end\n    local now = os.time()\n    local dx = now - d\n    if dx < 600 then\n        return '刚刚'\n    elseif dx < 3600 then\n        return math.floor(dx / 60) .. '分钟前'\n    elseif dx < 3600 * 24 then\n        return math.floor(dx / 3600) .. '小时前'\n    else\n        return os.date('%y-%m-%d', d)\n    end\nend\n\nlocal function getData(params, data, adapter, fragment, swipe_layout, reload)\n    local url = string.format('https://api.readhub.me/%s?pageSize=10', params.rid)\n    \n    if params.lastId then  \n        url = string.format('https://api.readhub.me/%s?lastCursor=%d&pageSize=10', params.rid, tonumber(params.lastId))\n    end\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then return end\n        local json = JSON.decode(body) \n        local arr = json.data\n        local lastItem = arr[#arr]\n        log.print_r(lastItem)\n        if lastItem.order then \n            params.lastId = lastItem.order\n        else\n            local y,m,d,h,M,s = string.match(lastItem.publishDate,'(%d%d%d%d)[-](%d%d)[-](%d%d)T(%d%d):(%d%d):(%d%d).')\n            a = { year = y, month = m, day = d, hour = h+8, min = M, sec=s}\n            params.lastId = os.time(a) * 1000\n        end\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                for k, _ in ipairs(data) do data[k] = nil end\n            end\n            local s = #data\n            for i = 1, #arr do\n                data[#data + 1] = arr[i]\n            end\n            adapter.notifyDataSetChanged()\n            swipe_layout.setRefreshing(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, item)\n    local url\n    if item.newsArray and #item.newsArray > 0 then\n        url = item.newsArray[1].mobileUrl\n    end\n\n    if item.url then url = item.url end\n\n    if url == nil then return end\n    local activity = fragment.getActivity()\n    WebViewActivity.start(activity,url, 0xff406d91)\n    \nend\n\nlocal function newInstance(rid)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            ListView,\n            id = \"listview\",\n            background = '#EEEEEE',\n            dividerHeight = 0,\n            paddingTop = \"8dp\",\n            clipToPadding = false,\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        FrameLayout,\n        layout_width = \"fill\",\n        {\n            LinearLayout,\n            background = '#FFFFFF',\n            layout_marginLeft = \"16dp\",\n            layout_marginRight = \"16dp\",\n            layout_marginTop = \"8dp\",\n            layout_marginBottom = \"8dp\",\n            elevation = \"2dp\",\n            orientation = 'vertical',\n            layout_width = \"fill\",\n            {\n                TextView,\n                id = \"tv_title\",\n                layout_width = \"fill\",\n                layout_margin = '16dp',\n                maxLines = 2,\n                lineSpacingMultiplier = 1.3,\n                textSize = \"16sp\",\n                textColor = \"#434343\",\n            },\n            {\n                TextView,\n                id = \"tv_time\",\n                layout_width = \"fill\",\n                layout_marginLeft = '16dp',\n                layout_marginRight = '16dp',\n                layout_marginBottom = '16dp',\n                maxLines = 4,\n                lineSpacingMultiplier = 1.3,\n                textSize = \"12sp\",\n                textColor = \"#666666\",\n            },\n        },\n    }\n\n\n    local hadLoadData\n    local isVisible\n    local lastId\n    local params = { rid = rid }\n    local data = {}\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(params, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        convertView.getLayoutParams().width = parent.getWidth()\n                        convertView.setTag(views)\n                        views.tv_title.setTypeface(nil, 1);\n                    end\n                    local views = convertView.getTag()\n                    local item = data[position]\n                    if item then\n                        views.tv_title.setText(item.title or 'ERROR TITLE')\n                        views.tv_time.setText( dateStr(item.updatedAt or item.publishDate or os.time() ))\n                    end\n                    if position == #data then getData(params, data, adapter, fragment, ids.swipe_layout) end\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    launchDetail(fragment, data[position + 1])\n                end,\n            }))\n            ids.swipe_layout.setRefreshing(true)\n            ids.swipe_layout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    getData(params, data, adapter, fragment, ids.swipe_layout, true)\n                end\n            }))\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/readhub/info.json",
    "content": "{\n  \"id\": \"pub.hanks.readhub\",\n  \"name\": \"ReadHub\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b0887dffcca79a?w=150&h=150&f=png&s=2619\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0\",\n  \"versionCode\": 2,\n  \"desc\": \"ReadHub\"\n}\n"
  },
  {
    "path": "lua/readhub/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"pub.hydrogen.android.R\"\nimport \"android.net.Uri\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal fragmentNews = require \"readhub/fragment_news\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#FFFFFF\",\n    {\n        Toolbar,\n        background = '#FFFFFF',\n        id = 'toolbar',\n        layout_width = \"match\",\n        layout_height = \"56dp\",\n        titleTextColor = \"#434343\",\n    },\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#FFFFFF\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\ntable.insert(data.fragments, fragmentNews.newInstance('topic'))\ntable.insert(data.titles, '热门话题')\n\ntable.insert(data.fragments, fragmentNews.newInstance('news'))\ntable.insert(data.titles, '科技动态')\n\ntable.insert(data.fragments, fragmentNews.newInstance('technews'))\ntable.insert(data.titles, '开发者资讯')\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    activity.setSupportActionBar(toolbar)\n    activity.setStatusBarColor(0x33000000)\n    activity.setTitle('ReadHub')\n    toolbar.setNavigationIcon(LuaDrawable.create('readhub/readhub.png'))\n    viewPager.setAdapter(adapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\n    tab.setSelectedTabIndicatorColor(0xff434343)\n    tab.setTabTextColors(0x88434343, 0xff434343)\n    tab.setTabMode(TabLayout.MODE_FIXED)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n\nfunction onCreateOptionsMenu(menu)\n    menu.add(\"网页版\")\n    return true\nend\n\nfunction onOptionsItemSelected(item)\n    local title = item.getTitle()\n    if title == \"网页版\" then\n        activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse('https://readhub.me/')))\n    end\nend"
  },
  {
    "path": "lua/splash/info.json",
    "content": "{\n  \"id\": \"pub.hanks.splash\",\n  \"name\": \"启动图\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088776a2871cb?w=150&h=150&f=png&s=1915\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0\",\n  \"versionCode\": 3,\n  \"desc\": \"每日启动图回顾\"\n}\n"
  },
  {
    "path": "lua/splash/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- qiqu\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"androlua.adapter.LuaPagerAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.app.DownloadManager\"\nimport \"android.os.Environment\"\nimport \"android.net.Uri\"\nlocal DialogBuilder = import \"android.app.AlertDialog$Builder\"\nlocal DownloadManagerRequest = import \"android.app.DownloadManager$Request\"\n\nlocal uihelper = require('uihelper')\nlocal JSON = require(\"cjson\")\n-- create view table\nlocal layout = {\n    FrameLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        ViewPager,\n        id = \"viewPager\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n    {\n        LinearLayout,\n        layout_width = \"fill\",\n        layout_gravity = \"bottom\",\n        orientation = \"vertical\",\n        paddingBottom = \"24dp\",\n        paddingLeft = \"20dp\",\n        paddingRight = \"20dp\",\n        paddingTop = \"120dp\",\n        background = \"@drawable/shadow_splash\",\n        {\n            RelativeLayout,\n            layout_width = \"fill\",\n            layout_height = \"40dp\",\n            layout_marginBottom = \"20dp\",\n            {\n                TextView,\n                id = \"tv_date\",\n                layout_alignParentRight = true,\n                layout_alignParentBottom = true,\n                textSize = \"14sp\",\n                textColor = \"#FFFFFF\",\n            },\n            {\n                TextView,\n                id = \"tv_day\",\n                layout_toLeftOf = \"tv_date\",\n                layout_alignBaseline = \"tv_date\",\n                textSize = \"30sp\",\n                gravity = \"right\",\n                textColor = \"#FFFFFF\",\n            },\n        },\n        {\n            TextView,\n            id = \"tv_text\",\n            layout_width = \"match\",\n            gravity = \"right\",\n            lineSpacingMultiplier = 1.5,\n            textSize = \"14sp\",\n            textColor = \"#FFFFFF\",\n        },\n    }\n}\n\nlocal item_view = {\n    ImageView,\n    id = \"iv_bg\",\n    layout_width = \"match\",\n    layout_height = \"match\",\n    scaleType = \"centerCrop\",\n}\n\nlocal adapter\nlocal data = {}\n\nlocal function downloadPicture(url)\n    local manager = activity.getSystemService(Context.DOWNLOAD_SERVICE)\n    local request = DownloadManagerRequest(Uri.parse(url))\n    request.setNotificationVisibility(DownloadManagerRequest.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);\n    request.setDescription(\"下载中...\")\n    request.setTitle(\"下载\")\n    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_PICTURES, os.time() .. \".jpg\")\n    manager.enqueue(request)\nend\n\nlocal function getData()\n    LuaHttp.request({ url = 'https://coding.net/u/zhangyuhan/p/api_luanroid/git/raw/master/api/splash' }, function(e, code, body)\n        print(body)\n        local json = JSON.decode(body)\n        local arr = json.data\n        uihelper.runOnUiThread(activity, function()\n            local views = {}\n            for i = 1, #arr do\n                data[#data + 1] = arr[i]\n                local ids = {}\n                local view = loadlayout(item_view, ids, ViewGroup)\n                LuaImageLoader.load(ids.iv_bg, arr[i].img)\n                ids.iv_bg.onClick = function()\n                    DialogBuilder(activity).setTitle('保存图片').setMessage('保存到相册？').setNegativeButton('取消', nil).setPositiveButton('确定', luajava.createProxy('android.content.DialogInterface$OnClickListener', {\n                        onClick = function(dialog, which)\n                            downloadPicture(arr[i].img)\n                            activity.toast('保存到相册...')\n                        end\n                    })).show()\n                end\n                views[#views + 1] = view\n            end\n            adapter.addViews(views)\n            adapter.notifyDataSetChanged()\n            if #data > 0 then\n                tv_date.setText(string.format('%d月', tonumber(data[1].date:sub(5, 6))))\n                tv_day.setText(string.format('%d/', tonumber(data[1].date:sub(7, 8))))\n                tv_text.setText(data[1].text)\n            end\n        end)\n    end)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x00000000)\n    activity.setContentView(loadlayout(layout))\n    adapter = LuaPagerAdapter(nil)\n    viewPager.setAdapter(adapter)\n    viewPager.addOnPageChangeListener(luajava.createProxy('android.support.v4.view.ViewPager$OnPageChangeListener', {\n        onPageSelected = function(position)\n            position = position + 1\n            local item = data[position]\n            tv_date.setText(string.format('/%d月', tonumber(item.date:sub(5, 6))))\n            tv_day.setText(string.format('%d', tonumber(item.date:sub(7, 8))))\n            tv_text.setText(item.text)\n        end\n    }))\n    getData()\nend\n"
  },
  {
    "path": "lua/sspai/activity_news_detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nlocal uihelper = require \"uihelper\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#D8171C\",\n    {\n        LinearLayout,\n        orientation = \"horizontal\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#D8171C\",\n        gravity = \"center_vertical\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginLeft = \"8dp\",\n            scaleType = \"centerInside\",\n            src = \"@drawable/ic_menu_back\",\n        },\n        {\n            TextView,\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            singleLine = true,\n            textIsSelectable = true,\n            ellipsize = \"end\",\n            id = \"tv_title\",\n            gravity = \"center_vertical\",\n            paddingLeft = \"8dp\",\n            textColor = \"#ffffff\",\n            textSize = \"16sp\",\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            LuaWebView,\n            id = \"webview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal css = [[\n    video{width:100%}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-webkit-text-size-adjust:100%}body{font-family:'Helvetica Neue',Helvetica,Arial,Sans-serif;background:#fff;padding-top:0;margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0}h1,h2,h3,h4,h5,h6{font-size:16px}abbr[title]{border-bottom:1px dotted}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:\\201C\\201D\\2018\\2019}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0;vertical-align:middle;color:transparent;font-size:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}table{border-collapse:collapse;border-spacing:0;overflow:hidden}a{text-decoration:none}blockquote{border-left:3px solid #d0e5f2;font-style:normal;display:block;vertical-align:baseline;font-size:100%;margin:.5em 0;padding:0 0 0 1em}ul,ol{padding-left:20px}.content{color:#444;line-height:1.6em;font-size:16px;margin:16px}.content img{max-width:100%;display:block;margin:30px auto}.content img+img{margin-top:15px}.content img[src*=\"zhihu.com/equation\"]{display:inline-block;margin:0 3px}.content a{color:#259}.content a:hover{text-decoration:underline}\n]]\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html>\n<head>\n    <title></title>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width; initial-scale=1; minimum-scale=1; maximum-scale=2\">\n    <meta content=\"width=device-width,user-scalable=no\" name=\"viewport\">\n    <style type=\"text/css\"> %s </style>\n</head>\n<body>\n<div class=\"content\"> %s </div>\n<script type=\"text/javascript\">\nfunction openImgActivity(a,b){var c=JSON.stringify({currentIndex:b,uris:a});var d=\"hydrogen://pub.hydrogen.android?action=open_img&data=\"+c;var e=document.createElement(\"iframe\");e.src=d;e.style.display=\"none\";document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},2000)}function init(){var a=document.querySelectorAll(\".content img\");for(var b=0;b<a.length;b++){a[b].addEventListener(\"click\",function(g){var e=g.target||g.srcElement;var c=[];var d=0;var h=document.querySelectorAll(\".content img\");for(var f=0;f<h.length;f++){c[f]=h[f].getAttribute(\"src\");if(e.getAttribute(\"src\").indexOf(c[f])!=-1){d=f}}openImgActivity(c,d)})}}init();\n</script>\n</body>\n</html>\n]]\n\n\nlocal function getData(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local content = string.match(body, 'class=\"content%s+wangEditor[-]txt.->(.-)</div>'):gsub('style=\".-\"', ''):gsub('width=%d+', ''):gsub('height=%d+', '')\n        local data = string.format(htmlTemplate, css, content)\n        uihelper.runOnUiThread(activity, function()\n            webview.loadData(data, \"text/html; charset=UTF-8\", nil)\n        end)\n    end)\nend\n\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    back.onClick = function()\n        activity.finish()\n    end\n    local url = activity.getIntent().getStringExtra('url')\n    tv_title.setText(url)\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    getData(url)\nend\n\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend\n"
  },
  {
    "path": "lua/sspai/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.os.Build\"\nlocal Orientation = import \"android.graphics.drawable.GradientDrawable$Orientation\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\n\nlocal colors = luajava.createArray(\"int\", { 0x77000000, 0x00000000 })\nlocal gd = GradientDrawable(Orientation.TOP_BOTTOM, colors)\ngd.setCornerRadius(uihelper.dp2px(3))\n\nlocal function getData(params, data, adapter, fragment, swipe_layout, reload)\n    local url = string.format('https://api.qingmang.me/v2/article.list?token=c400a7e21688496ca3e7f17c6b0d1846&category_id=%s', params.rid)\n    if params.nextUrl then url = params.nextUrl end\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then return end\n        local json = JSON.decode(body)\n        if json.hasMore and json.nextUrl then params.nextUrl = json.nextUrl end\n        local arr = json.articles\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                for k, _ in pairs(data) do data[k] = nil end\n            end\n            local s = #data\n            for i = 1, #arr do\n                data[#data + 1] = arr[i]\n            end\n            adapter.notifyDataSetChanged()\n            swipe_layout.setRefreshing(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, item)\n    local activity = fragment.getActivity()\n    if item == nil or item.webUrl == nil then\n        activity.toast('没有 url 可以打开')\n        return\n    end\n    local activity = fragment.getActivity()\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'sspai/activity_news_detail.lua')\n    intent.putExtra(\"url\", item.webUrl)\n    activity.startActivity(intent)\nend\n\nlocal function newInstance(rid)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            ListView,\n            id = \"listview\",\n            background = '#FFFFFF',\n            dividerHeight = 0,\n            paddingTop = \"16dp\",\n            clipToPadding = false,\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        LinearLayout,\n        background = '#ffffff',\n        orientation = 'vertical',\n        layout_width = \"fill\",\n        {\n            FrameLayout,\n            layout_marginLeft = '16dp',\n            layout_marginRight = '16dp',\n            layout_width = \"fill\",\n            layout_height = \"140dp\",\n            {\n                ImageView,\n                id = \"iv_image\",\n                layout_width = \"fill\",\n                layout_height = \"fill\",\n                scaleType = \"centerCrop\",\n            },\n            {\n                View,\n                background = gd,\n                layout_width = \"fill\",\n                layout_height = \"90dp\",\n            },\n            {\n                TextView,\n                id = \"tv_title\",\n                layout_width = \"fill\",\n                layout_marginLeft = '16dp',\n                layout_marginRight = '16dp',\n                layout_marginTop = '8dp',\n                maxLines = 2,\n                lineSpacingMultiplier = 1.3,\n                textSize = \"16sp\",\n                textColor = \"#EEFFFFFF\",\n            },\n        },\n        {\n            TextView,\n            id = \"tv_desc\",\n            layout_width = \"fill\",\n            layout_marginTop = '8dp',\n            layout_marginLeft = '16dp',\n            layout_marginRight = '16dp',\n            layout_marginBottom = '16dp',\n            maxLines = 4,\n            lineSpacingMultiplier = 1.3,\n            textSize = \"12sp\",\n            textColor = \"#666666\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"16dp\",\n        }\n    }\n\n\n    local hadLoadData\n    local isVisible\n    local lastId\n    local params = { rid = rid }\n    local data = {}\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(params, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        convertView.getLayoutParams().width = parent.getWidth()\n                        convertView.setTag(views)\n                    end\n                    local views = convertView.getTag()\n                    local item = data[position]\n                    if item then\n                        if item.covers and #item.covers > 0 then\n                            views.iv_image.setVisibility(0)\n                            LuaImageLoader.loadWithRadius(views.iv_image, 3, item.covers[1].url .. '?imageMogr2/quality/95/thumbnail/!1440x480r/gravity/Center/crop/1440x480')\n                        else\n                            views.iv_image.setVisibility(8)\n                        end\n                        views.tv_title.setText(item.title or 'ERROR TITLE')\n                        views.tv_desc.setText(item.snippet or '')\n                    end\n                    if position == #data then getData(params, data, adapter, fragment, ids.swipe_layout) end\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    launchDetail(fragment, data[position + 1])\n                end,\n            }))\n            ids.swipe_layout.setRefreshing(true)\n            ids.swipe_layout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    getData(params, data, adapter, fragment, ids.swipe_layout, true)\n                end\n            }))\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/sspai/info.json",
    "content": "{\n  \"id\": \"pub.hanks.sspai\",\n  \"name\": \"少数派\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b088719a5dfd47?w=150&h=150&f=png&s=2762\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.2\",\n  \"versionCode\": 4,\n  \"desc\": \"少数派\"\n}\n"
  },
  {
    "path": "lua/sspai/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\n\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal fragmentNews = require \"sspai/fragment_news\"\n\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#D8171C\",\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#D8171C\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\n\ntable.insert(data.fragments, fragmentNews.newInstance('p14'))\ntable.insert(data.titles, '每日更新')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p15756'))\ntable.insert(data.titles, 'Matrix')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p15757'))\ntable.insert(data.titles, '效率工具')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p15912'))\ntable.insert(data.titles, '手机摄影')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p15913'))\ntable.insert(data.titles, '生活方式')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p15914'))\ntable.insert(data.titles, '游戏')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p15104'))\ntable.insert(data.titles, '硬件')\n\ntable.insert(data.fragments, fragmentNews.newInstance('p15915'))\ntable.insert(data.titles, '人物')\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    viewPager.setAdapter(adapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\n    tab.setSelectedTabIndicatorColor(0xffffffff)\n    tab.setTabTextColors(0x88ffffff, 0xffffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n"
  },
  {
    "path": "lua/taobao/info.json",
    "content": "{\n  \"id\": \"pub.hanks.taobao\",\n  \"name\": \"淘宝\",\n  \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fikliu17ghj2046046jr6.jpg\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.0\",\n  \"versionCode\": 1,\n  \"private\": true,\n  \"desc\": \"轻版淘宝\"\n}\n"
  },
  {
    "path": "lua/taobao/main.lua",
    "content": "require \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.view.View\"\nimport \"java.net.URL\"\nimport \"android.net.Uri\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"pub.hydrogen.android.R\"\nimport \"android.support.design.widget.FloatingActionButton\"\nimport \"androlua.utils.ColorStateListFactory\"\nimport \"java.lang.String\"\nimport \"android.graphics.drawable.GradientDrawable\"\n\nlocal DialogBuilder = import \"android.app.AlertDialog$Builder\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\n\n\n\nlocal tabTypes = {'all','mall'}\nlocal adapter\nlocal data = {}\nlocal page = 1\nlocal sort = \"\"\nlocal tab = tabTypes[1]\n\nlocal filter = {\n    start_price=-1,\n    end_price=-1,\n    filter={}\n}\n\nlocal bg_selector = GradientDrawable()\nbg_selector.setColor(ColorStateListFactory.newInstance(0x11ffffff,0xffff0000))\n\nactivity.setTheme(R.style.Theme_AppCompat_NoActionBar)\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"match\",\n    layout_height = \"match\",\n    orientation = \"vertical\",\n    statusBarColor = \"#ff5500\",\n    {\n        Toolbar,\n        background = '#ff5500',\n        id = 'toolbar',\n        layout_width = \"match\",\n        layout_height = \"56dp\",\n        titleTextColor = \"#ffffff\",\n        popupTheme = R.style.ThemeOverlay_AppCompat_Light,\n        {\n            RelativeLayout,\n            layout_width = \"match\",\n            layout_height = \"match\",\n            {\n                EditText,\n                id = 'et_key',\n                layout_width = \"match\",\n                layout_height = \"match\",\n                maxLines = 1,\n                singleLine = true,\n                textColor = '#ffffff',\n                hintTextColor = '#88ffffff',\n                background = '#00ffffff',\n                hint = \"搜索商品\",\n                textColor = \"#FFFFFF\",\n            }, \n            {\n                ImageView,\n                layout_centerVertical = true,\n                layout_alignParentRight = true,\n                layout_marginRight = '16dp',\n                src = '#taobao/ic_search.png',\n                id = 'bt_search',\n            },\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"match\",\n        layout_height = \"match\",\n        {\n            SwipeRefreshLayout,\n            id = \"refreshLayout\",\n            layout_width = \"match\",\n            {\n                RecyclerView,\n                background = '#ffffff',\n                id = \"recyclerView\",\n                layout_width = \"fill\",\n                layout_height = \"fill\",\n            },\n        },\n        {\n            FloatingActionButton, \n            id = 'fab',\n            src = '#taobao/ic_sort.png',\n            backgroundTintList = ColorStateListFactory.newInstance(0xFFFF5500),\n            layout_gravity = 85,\n            layout_margin = '16dp',\n        },\n    }\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    layout_height = \"132dp\",\n    paddingLeft = \"12dp\",\n    paddingRight = \"12dp\",\n    paddingTop = \"16dp\",\n    {\n        ImageView,\n        id = 'iv_image',\n        layout_width = \"100dp\",\n        layout_height = \"100dp\",\n    },\n    {\n        TextView,\n        id = \"tv_title\",\n        layout_marginLeft = \"108dp\",\n        textColor = \"#4b566a\",\n        lineSpacingMultiplier = 1.3,\n        textSize = \"14sp\",\n        maxLines = 2,\n    },\n    {\n        TextView,\n        id = \"tv_money\",\n        layout_marginLeft = \"108dp\",\n        layout_marginBottom = \"40dp\",\n        maxLines = 1,\n        textSize = \"17sp\",\n        textColor = \"#ff5500\",\n        layout_gravity = \"bottom\",\n    },\n    {\n        TextView,\n        id = \"tv_info\",\n        layout_marginLeft = \"108dp\",\n        layout_marginBottom = \"16dp\",\n        maxLines = 1,\n        textSize = \"10sp\",\n        textColor = \"#999999\",\n        layout_gravity = \"bottom\",\n    },\n    {\n        View,\n        layout_width = 'match',\n        layout_height = '0.5dp',\n        background = '#eeeeee',\n        layout_gravity = \"bottom\",\n    },\n}\n\nlocal sortTypes = {\n    names = {\"综合排序\",\"销量优先\",\"价格从高到低\",\"价格从低到高\",\"信用排序\"},\n    keys = {\"\",\"_sale\",\"_bid\",\"bid\",\"_ratesum\"}\n}\n\nlocal function resetFilter()\n    filter.start_price = -1\n    filter.end_price = -1\n    for i=1,#filter.filter do\n        filter.filter[i] = nil\n    end\nend\n\nlocal function launchDetail(msg)\n    if msg and msg.url then\n        local url = msg.url\n        if url:find('^//') then url = 'https:' .. url end\n        WebViewActivity.start(activity, url, 0xFFFF5500)\n        return\n    end\n\n    activity.toast('没有 url 可以打开')\nend\n\nlocal function launchPicturePreview(msg, index)\n    local urls = {}\n    for i = 1, #msg.mblog.pics do\n        urls[i] = msg.mblog.pics[i].large.url\n    end\n    local data = {\n        uris = urls,\n        currentIndex = index\n    }\n    PicturePreviewActivity.start(activity, JSON.encode(data))\nend\n\n\nlocal function fetchData(loadMore)\n    -- &start_price=2&end_price=3333333&filter=service_myf\n    -- https://s.m.taobao.com/search?q=多肉&sst=1&n=20&buying=buyitnow&m=api4h5&abtest=7&wlsort=7&style=list&closeModues=nav%2Cselecthot%2Conesearch&sort=_sale&page=1\n    local key = et_key.getText().toString()\n    if key==nil or key == '' then \n        refreshLayout.setRefreshing(false)\n        return\n    end\n    local url = string.format(\"https://s.m.taobao.com/search?q=%s&tab=%s&sst=1&n=20&buying=buyitnow&m=api4h5&abtest=6&wlsort=6&sort=%s&page=%d\",key,tab,sort,page)\n    local t = {}\n    if filter.start_price > 0 then t[#t+1] = string.format('&start_price=%d',filter.start_price) end\n    if filter.end_price > 0 then t[#t+1] = string.format('&end_price=%d',filter.end_price) end\n    if #filter.filter > 0 then t[#t+1] = '&filter=' .. table.concat( filter.filter, \";\") end\n    if #t>0 then url = url .. table.concat( t, \"\") end\n    print(url)\n\n    local options = {\n        url = url,\n    }\n    LuaHttp.request(options, function(error, code, body)\n        if error or code ~= 200 then\n            activity.toast('网络错误')\n            refreshLayout.setRefreshing(false)\n            return\n        end\n        local listItem = JSON.decode(body).listItem\n        if listItem == nil then\n            listItem = {}\n        end\n        uihelper.runOnUiThread(activity, function()\n            if page == 1 then\n                for k, _ in pairs(data) do data[k] = nil end\n            end\n            local s = #data\n            for i = 1, #listItem do\n                local item = listItem[i]\n                data[#data + 1] = item\n            end\n            page = page + 1\n            if loadMore then\n                adapter.notifyItemRangeChanged(s, #data)\n            else\n                adapter.notifyDataSetChanged()\n            end\n            refreshLayout.setRefreshing(false)\n        end)\n    end)\nend\n\n\nlocal function reload(  )\n    refreshLayout.setRefreshing(true)\n    page = 1\n    fetchData() \nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0xFFFF5500)\n    activity.setContentView(loadlayout(layout))\n    activity.setSupportActionBar(toolbar)\n    activity.setTitle('淘宝')\n    toolbar.setTitle('淘宝')\n    toolbar.setNavigationIcon(LuaDrawable.create('taobao/taobao.png'))\n    toolbar.setNavigationOnClickListener(luajava.createProxy('android.view.View$OnClickListener',{\n        onClick = function()\n            if tab == tabTypes[1] then\n                tab = tabTypes[2]\n                toolbar.setNavigationIcon(LuaDrawable.create('taobao/tmall.png'))\n            else\n                tab = tabTypes[1]\n                toolbar.setNavigationIcon(LuaDrawable.create('taobao/taobao.png'))\n            end\n            reload()\n        end\n    }))\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function() return #data end,\n        getItemViewType = function(position) return 0 end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.getLayoutParams().width = parent.getWidth()\n            holder.itemView.setTag(views)\n            holder.itemView.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1,\n                print(position)\n                launchDetail(data[position])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local msg = data[position]\n            local views = holder.itemView.getTag()\n            views.tv_title.setText(msg.title)\n            views.tv_money.setText( '¥' .. msg.price)\n            local fee = '免运费'\n            local f = tonumber(msg.fastPostFee);\n            if f and f > 0 then fee = '运费' .. f end\n            views.tv_info.setText(string.format('%s    %s 人付款    %s',fee, msg.act,msg.area))\n            LuaImageLoader.load(views.iv_image, 'https:'..msg.img2)\n            if position == #data then fetchData(true) end\n        end,\n    }))\n    recyclerView.setLayoutManager(LinearLayoutManager(activity))\n    recyclerView.setAdapter(adapter)\n    refreshLayout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n        onRefresh = function()\n            reload()\n        end\n    }))\n    bt_search.onClick = function()\n       resetFilter()\n       reload()   \n    end\n\n    et_key.setImeOptions(0x00000003)\n    et_key.setOnEditorActionListener(luajava.createProxy('android.widget.TextView$OnEditorActionListener', {\n        onEditorAction = function(v, actionId, event)\n            resetFilter()\n            reload()\n            return false\n        end\n    }))\n\n    fab.onClick = function()\n        local choiceItem = 1\n        for i=1,#sortTypes.keys do\n            if sort == sortTypes.keys[i] then\n                choiceItem = i\n            end\n        end\n        DialogBuilder(activity)\n        .setSingleChoiceItems(sortTypes.names,choiceItem-1,luajava.createProxy('android.content.DialogInterface$OnClickListener',{\n            onClick = function(dialog, which )\n                dialog.dismiss()\n                sort = sortTypes.keys[which+1]\n                reload()\n            end\n        }))\n        .show()\n    end\nend\n\nfunction onCreateOptionsMenu(menu)\n    menu.add(\"过滤\").setIcon(LuaDrawable.create('taobao/ic_filter.png')).setShowAsAction(2)\n    menu.add(\"网页版\")\n    return true\nend\n\n\nlocal function showFilterView()\n    \n    local function findCheck( parent )\n       local c = parent.getChildCount()\n       for i=1,c do\n           local view = parent.getChildAt(i-1)\n           if view.isSelected() then\n                filter.filter[#filter.filter + 1] = view.getTag()\n           end\n       end\n    end\n\n    local function toggleCheck(v )\n        v.setSelected(not v.isSelected())\n        local bgColor = 0x11ffffff\n        if v.isSelected() then bgColor = 0x55ffffff end\n        v.setBackgroundColor(bgColor)\n    end\n\n    local function title( text )\n        return {\n            TextView,\n            layout_marginTop = \"16dp\",\n            layout_marginBottom = \"8dp\",\n            text = text,\n            textSize = '16sp',\n        }\n    end\n\n    local function checkText(text,key)\n        local selected = false\n        for i=1,#filter.filter do\n            if filter.filter[i] == key then\n                selected = true\n            end\n        end\n        local bgColor = 0x11ffffff\n        if selected then bgColor = 0x55ffffff end \n        return \n        {\n            TextView,\n            backgroundColor = bgColor,\n            gravity = \"center\",\n            layout_weight = 1,\n            layout_height = '30dp',\n            layout_marginRight = \"8dp\",\n            layout_marginTop= \"8dp\",\n            text = text,\n            textSize = '12sp',\n            tag = key,\n            clickable = true,\n            selected = selected,\n            onClick = toggleCheck,\n        }\n    end\n\n    local filter_view = {\n        LinearLayout,\n        orientation=\"vertical\",\n        layout_width = \"fill\",\n        padding = '16dp',\n        title(\"价格区间\"),\n        {\n            LinearLayout,\n            layout_width = \"fill\",\n            gravity= \"center_vertical\",\n            {EditText, id = \"et_price_start\", textSize='13sp', layout_width = '100dp', hint = '最低价', inputType = \"number\", },\n            {View, layout_height = \"1dp\",  layout_width = \"8dp\", background = \"#eeeeee\", layout_margin = \"4dp\", },\n            {EditText, id = \"et_price_end\", textSize='13sp', layout_width = '100dp', hint = '最高价', inputType = \"number\", }, \n        },\n        title(\"折扣和服务\"),\n        {\n            LinearLayout,\n            id = \"layout_zk_1\",\n            layout_width = \"fill\",\n            checkText(\"免运费\",\"service_myf\"),\n            checkText(\"天猫\",\"tab_mall\"),\n            checkText(\"全球购\",\"service_hwsp\"),\n        },\n        {\n            LinearLayout,\n            id = \"layout_zk_2\",\n            layout_width = \"fill\",\n            checkText(\"消费者保障\",\"service_xfzbz\"),\n            checkText(\"手机专享价\",\"service_sjzx\"),\n            checkText(\"淘金币\",\"service_tjb\"),\n        },\n        {\n            LinearLayout,\n            id = \"layout_zk_3\",\n            layout_width = \"fill\",\n            checkText(\"促销\",\"tab_discount\"),\n            checkText(\"7天退换\",\"service_qtth\"),\n            checkText(\"货到付款\",\"service_hdfk\"),\n        },\n    }\n\n    local views = {}\n    local view = loadlayout(filter_view,views,ViewGroup)\n    if filter.start_price > 0 then views.et_price_start.setText(''..filter.start_price) end\n    if filter.end_price >0 then views.et_price_end.setText(''..filter.end_price) end\n    DialogBuilder(activity).setView(view).setNegativeButton('取消', nil).setPositiveButton('确定', luajava.createProxy('android.content.DialogInterface$OnClickListener', {\n        onClick = function(dialog, which)\n\n            resetFilter()\n\n            local p_s = views.et_price_start.getText().toString()\n            if p_s and p_s ~= '' then filter.start_price = tonumber(p_s) end\n\n            local p_e = views.et_price_end.getText().toString()\n            if p_e and p_e ~= '' then filter.end_price = tonumber(p_e) end\n\n            findCheck(views.layout_zk_1)\n            findCheck(views.layout_zk_2)\n            findCheck(views.layout_zk_3)\n\n            if filter.start_price > filter.end_price then filter.start_price,filter.end_price = filter.end_price,filter.start_price end\n            log.print_r(filter)\n            reload()\n        end\n    })).show()\nend \n\nfunction onOptionsItemSelected(item)\n    local title = item.getTitle()\n    if title == \"网页版\" then\n        activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse('https://s.m.taobao.com/h5')))\n    elseif title == '过滤'  then\n       showFilterView()\n    end\nend\n\n\n"
  },
  {
    "path": "lua/tieba/activity_news_detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\nlocal log = require(\"log\")\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#ff198ef1\",\n    {\n        LinearLayout,\n        orientation = \"horizontal\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#ff198ef1\",\n        gravity = \"center_vertical\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginLeft = \"8dp\",\n            scaleType = \"centerInside\",\n            src = \"@drawable/ic_menu_back\",\n        },\n        {\n            TextView,\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            singleLine = true,\n            textIsSelectable = true,\n            ellipsize = \"end\",\n            id = \"tv_title\",\n            gravity = \"center_vertical\",\n            paddingLeft = \"8dp\",\n            textColor = \"#ffffff\",\n            textSize = \"18sp\",\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            LuaWebView,\n            id = \"webview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal css = [[\n    article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-webkit-text-size-adjust:100%}body{font-family:'Helvetica Neue',Helvetica,Arial,Sans-serif;background:#fff;padding-top:0;margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0}h1,h2,h3,h4,h5,h6{font-size:16px}abbr[title]{border-bottom:1px dotted}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:\\201C\\201D\\2018\\2019}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0;vertical-align:middle;color:transparent;font-size:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}table{border-collapse:collapse;border-spacing:0;overflow:hidden}a{text-decoration:none}blockquote{border-left:3px solid #d0e5f2;font-style:normal;display:block;vertical-align:baseline;font-size:100%;margin:.5em 0;padding:0 0 0 1em}ul,ol{padding-left:20px}.content{color:#444;line-height:1.6em;font-size:16px;margin:16px 16px 0 16px;}.content img{max-width:100%;margin:4px auto}.content img+img{margin-top:15px}.content img[src*=\"zhihu.com/equation\"]{display:inline-block;margin:0 3px}.content a{color:#259}.content a:hover{text-decoration:underline}\n    .i {border-bottom: 1px solid #EFEFEF; padding-top: 16px; padding-bottom: 16px; }  td.l,td.r{ font-size: 12px;} span.g{color: #5199E2;}\n]]\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html>\n<head>\n    <title>氢应用-贴吧</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,user-scalable=no\">\n    <style type=\"text/css\"> %s </style>\n</head>\n<body>\n<div id=\"list\" class=\"content\"> %s </div>\n<div id=\"more\" style=\"height:48px; line-height:48px; text-align:center;color: #569ADD;\">下一页</div> \n<script type=\"text/javascript\">\n\nfunction launchReply(lnk){\n    var s = {};\n    s.method = 'launchReply';\n    s.data = lnk;\n    window.luaApp.call(JSON.stringify(s));\n}\nfunction initLoadMore(){\n    document.getElementById('more').onclick = function() {\n        var s = {};\n        s.method = 'loadMore';\n        window.luaApp.call(JSON.stringify(s));\n        document.getElementById('more').textContent = '正在加载...'\n    }\n    var arr = document.querySelectorAll(\"div.i\");\n    for(var i=0;i<arr.length;i++){\n        var links = arr[i].querySelectorAll('uu[href]')\n        var lnk = ''\n        for(var j=0;j<links.length;j++){\n            lnk = links[j].getAttribute('href')\n            if (lnk.lastIndexOf('flr')>=0){\n                break;\n            }\n            lnk = ''\n        }\n        if (lnk != ''){\n            arr[i].onclick = (function(lnk){\n                return function() { launchReply(lnk) }\n            })(lnk)\n        }\n    }\n}\n\nfunction hideLoadMore(){\n    document.getElementById('more').style.display = 'none'\n}\n\nfunction openImgActivity(a, b) {\n    var c = JSON.stringify({\n        currentIndex: b,\n        uris: a\n    });\n    var d = \"hydrogen://pub.hydrogen.android?action=open_img&data=\" + c;\n    var e = document.createElement(\"iframe\");\n    e.src = d;\n    e.style.display = \"none\";\n    document.body.appendChild(e);\n    setTimeout(function() {\n        document.body.removeChild(e)\n    },\n    2000)\n}\n\nfunction previewImgage(g) {\n    g.stopPropagation()\n    var e = g.target || g.srcElement;\n    var c = [];\n    var d = 0;\n    var h = document.querySelectorAll(\".content img\");\n    for (var f = 0; f < h.length; f++) {\n        var url = h[f].getAttribute(\"src\"); \n        c[f] = 'http://imgsrc.baidu.com/forum/pic/item/' + url.match('[0-9a-z]*.jpg*$')\n        if (e.getAttribute(\"src\").indexOf(url) != -1) {\n            d = f\n        }\n    }\n    openImgActivity(c, d)\n}\n\nfunction init() {\n    var a = document.querySelectorAll(\".content img\");\n    for (var b = 0; b < a.length; b++) {\n        a[b].addEventListener(\"click\", previewImgage)\n    }\n}\nfunction appendList(h){\n    document.getElementById('more').textContent = '下一页'\n    var list = document.getElementById('list');\n    var newList = document.createElement('div');\n    newList.innerHTML = h;\n    list.appendChild(newList)\n    init();\n}\n\ninitLoadMore();\ninit();\n</script>\n</body>\n</html>\n]]\n\nlocal params = { rid, page = 0 }\n\nfunction html_unescape(s)\n    return s:gsub(\"&lt;\", \"<\"):gsub(\"&gt;\", \">\"):gsub(\"&amp;\", \"&\"):gsub(\"&quot;\", '\"'):gsub(\"&#39;\", \"'\"):gsub(\"&#47;\", \"/\")\nend\n\nlocal function getData(fromJs)\n\n    local url = string.format('http://c.tieba.baidu.com/mo/q----,sz@320_240-1-3---2/m?kz=%s&new_word=&pn=%d&lp=6021', params.rid, params.page * 30)\n    if params.pid and params.kid then\n        url = string.format('http://c.tieba.baidu.com/mo/q----,sz@320_240-1-3---2/flr?pid=%s&kz=%s&pn=%d&pinf=1_2_20', params.pid, params.kid, params.page * 30)\n    end\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local tag = 'class=\"d\">(.-)笑话大放送'\n        if params.pid and params.kid then\n            tag = 'class=\"m t\">(.-)</body>'\n        end\n        local content = string.match(body, tag)\n        content = html_unescape(content)\n        content = content:gsub('&quality=45&size=b96_2000', '&quality=80&size=b400_2000')\n        local nextUrl = string.find(content, '>下一页')\n        if nextUrl then\n            params.page = params.page + 1\n        end\n        content = content:gsub('<a href=', '<uu href='):gsub('</a>', '</uu>'):gsub('<form.->.-</form>', '')\n        local data = string.format(htmlTemplate, css, content)\n        uihelper.runOnUiThread(activity, function()\n            if nextUrl == nil then\n                webview.loadUrl(\"javascript:hideLoadMore()\")\n            end\n            if fromJs then\n                webview.loadUrl(string.format(\"javascript:appendList('%s')\", content))\n                return\n            end\n            webview.loadDataWithBaseURL(\"http://c.tieba.baidu.com/mo/q----,sz@320_240-1-3---2/\", data, \"text/html\", \"utf-8\", nil)\n        end)\n    end)\nend\n\nlocal function callback(jsonStr)\n    local json = JSON.decode(jsonStr)\n    if json.method == 'loadMore' then\n        getData(true)\n        return\n    end\n\n    if json.method == 'launchReply' then\n        local lnk = json.data\n        local item = {\n            reply = true,\n            title = '回复',\n            url = lnk\n        }\n        local intent = Intent(activity, LuaActivity)\n        intent.putExtra(\"luaPath\", 'tieba/activity_news_detail.lua')\n        intent.putExtra(\"item\", JSON.encode(item))\n        activity.startActivity(intent)\n        return\n    end\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    back.onClick = function()\n        activity.finish()\n    end\n\n    local str = activity.getIntent().getStringExtra(\"item\"):gsub('\\\\/', '/')\n    local item = JSON.decode(str)\n    tv_title.setText(item.title)\n    if item.reply then\n        local pid, kid = string.match(item.url, 'pid=(%d+)&kz=(%d+)')\n        params.pid = pid\n        params.kid = kid\n    else\n        params.rid = string.match(item.url, '/p/(%d+)')\n    end\n\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    getData()\n    webview.injectObjectToJavascript(callback, \"luaApp\")\nend\n\nfunction onBackPressed()\n    if webview.canGoBack() then webview.goBack() return true end\n    return false\nend\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend\n"
  },
  {
    "path": "lua/tieba/fragment_news.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.os.Build\"\nimport \"androlua.common.LuaToast\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\n\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\n\nlocal function cleanTag(text)\n    return text:gsub(\"<.->\", \"\"):gsub(\"^%s+\", \"\"):gsub(\"%s$\", \"\")\nend\n\nlocal function getData(params, data, adapter, fragment, swipe_layout, reload)\n    -- http://c.tieba.baidu.com/mo/q/m?kw=cxczxzxzxx&pn=0&lp=5024&forum_recommend=1&lm=0&cid=0&has_url_param=0&pn=50&is_ajax=1\n    -- http://c.tieba.baidu.com/mo/q/m?kw=河南理工大学&pn=0&lp=5024&forum_recommend=1&lm=0&cid=0&has_url_param=0&pn=50&is_ajax=1\n    local url = string.format('http://c.tieba.baidu.com/mo/q/m?kw=%s&pn=0&lp=5024&forum_recommend=1&lm=0&cid=0&has_url_param=0&pn=%d&is_ajax=1', params.rid, params.page * 50)\n    print(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then return end\n        local json = JSON.decode(body)\n        local isEnd = false\n        if params.page + 1 >= json.data.page.total_page then isEnd = true end\n        params.page = params.page + 1\n        local body = json.data.content:gsub('\\\\\"', '\"')\n--        print(body)\n        local arr = {}\n        local match_p = '<img src=\"(.-)\".-class=\"ti_author\">(.-)</span>.-class=\"ti_time\">(.-)</span>.-<a href=\"(.-)\"%s+class=\"j_common%s+ti_item%s+\".-<div class=\"ti_title\">(.-)</div>.-<div class=\"ti_func_btn btn_reply\">(.-)</div>'\n        local i = 0;\n        for tl_shadow in string.gmatch(body, '<li class=\"tl_shadow.-\">(.-)</li>') do\n            avatar, author, time, url, title, commentCount = string.match(tl_shadow, match_p)\n--            print(tl_shadow)\n            if title ~= nil and author ~= nil and time ~= nil and commentCount ~= nil then\n                local imgArr = {}\n                for img in string.gmatch(tl_shadow, 'medias_thumb_holder\".-data.url=\"(.-)\"') do\n                    imgArr[#imgArr + 1] = img\n                end\n                local item = {\n                    url = url,\n                    title = cleanTag(title),\n                    author = cleanTag(author),\n                    avatar = avatar,\n                    time = cleanTag(time),\n                    commentCount = cleanTag(commentCount),\n                    imgs = imgArr,\n                }\n                arr[#arr + 1] = item\n            end\n           \n        end\n\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if isEnd then LuaToast.show(\"finish!!!\") end\n            if reload then\n                for k, _ in ipairs(data) do data[k] = nil end\n            end\n            local s = #data\n            for i = 1, #arr do\n                local item = arr[i]\n                if item ~= nil and item.title ~= nil and item.title ~= \"\" then\n                    data[#data + 1] = item\n                end\n            end\n            adapter.notifyDataSetChanged()\n            swipe_layout.setRefreshing(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, item)\n    local activity = fragment.getActivity()\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'tieba/activity_news_detail.lua')\n    intent.putExtra(\"item\", JSON.encode(item))\n    activity.startActivity(intent)\nend\n\nlocal dividerHeight = uihelper.dp2px(8)\n\nlocal function preview(url)\n    local pid = string.match(url,'/([0-9a-z]-).jpg')\n    url = string.format('http://imgsrc.baidu.com/forum/pic/item/%s.jpg',  pid)\n    local args = { uris = { url }, currentIndex = 0 }\n    PicturePreviewActivity.start(activity, JSON.encode(args))\nend\n\nlocal function newInstance(rid)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            ListView,\n            id = \"listview\",\n            background = '#ebedf0',\n            dividerHeight = dividerHeight,\n            paddingTop = \"8dp\",\n            clipToPadding = false,\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        LinearLayout,\n        background = '#FFFFFF',\n        padding = \"12dp\",\n        orientation = 'vertical',\n        layout_width = \"fill\",\n        {\n            FrameLayout,\n            layout_width = \"fill\",\n            {\n                ImageView,\n                id = \"iv_avatar\",\n                layout_width = \"32dp\",\n                layout_height = \"32dp\",\n            },\n            {\n                TextView,\n                id = \"tv_author\",\n                textSize = \"13sp\",\n                textColor = \"#626466\",\n                layout_marginLeft = \"40dp\",\n            },\n            {\n                TextView,\n                id = \"tv_time\",\n                layout_width = \"100dp\",\n                textSize = \"11sp\",\n                layout_marginLeft = \"40dp\",\n                layout_marginTop = \"18dp\",\n                textColor = \"#abaeb2\",\n            },\n        },\n        {\n            TextView,\n            id = \"tv_title\",\n            layout_width = \"fill\",\n            maxLines = 2,\n            layout_marginTop = \"8dp\",\n            lineSpacingMultiplier = 1.3,\n            textSize = \"16sp\",\n            textColor = \"#262626\",\n        },\n        {\n            LinearLayout,\n            id = \"layout_image\",\n            {\n                ImageView,\n                id = \"iv_image1\",\n                layout_marginTop = '8dp',\n                layout_width = \"100dp\",\n                layout_height = \"100dp\",\n                scaleType = \"centerCrop\",\n            },\n            {\n                ImageView,\n                id = \"iv_image2\",\n                layout_marginTop = '8dp',\n                layout_marginLeft = '8dp',\n                layout_width = \"100dp\",\n                layout_height = \"100dp\",\n                scaleType = \"centerCrop\",\n            },\n            {\n                ImageView,\n                id = \"iv_image3\",\n                layout_marginTop = '8dp',\n                layout_marginLeft = '8dp',\n                layout_width = \"100dp\",\n                layout_height = \"100dp\",\n                scaleType = \"centerCrop\",\n            },\n        },\n        {\n            TextView,\n            layout_marginTop = '8dp',\n            layout_width = \"fill\",  \n            gravity = \"right\",\n            id = \"tv_comment_count\",\n            textSize = \"12sp\",\n            textColor = \"#7798ca\",\n        },\n    }\n\n\n    local hadLoadData\n    local isVisible\n    local lastId\n    local params = { rid = rid, page = 0 }\n    local data = {}\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(params, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        convertView.getLayoutParams().width = parent.getWidth()\n                        convertView.setTag(views)\n                        views.tv_title.setTypeface(nil, 1);\n                    end\n                    local views = convertView.getTag()\n                    local item = data[position]\n                    if item then\n                        \n                        if item.imgs and #item.imgs > 0 then\n                            views.layout_image.setVisibility(0)\n                            views.iv_image1.setVisibility(0)\n                            LuaImageLoader.load(views.iv_image1, item.imgs[1])\n                            views.iv_image1.onClick = function()\n                                preview(item.imgs[1])\n                            end\n                            if #item.imgs > 1 then\n                                views.iv_image2.setVisibility(0)\n                                LuaImageLoader.load(views.iv_image2, item.imgs[2])\n                                views.iv_image2.onClick = function()\n                                    preview(item.imgs[2])\n                                end\n                            else\n                                views.iv_image2.setVisibility(8)\n                            end\n\n                            if #item.imgs > 2 then\n                                views.iv_image3.setVisibility(0)\n                                LuaImageLoader.load(views.iv_image3, item.imgs[3])\n                                views.iv_image3.onClick = function()\n                                    preview(item.imgs[3])\n                                end\n                            else\n                                views.iv_image3.setVisibility(8)\n                            end\n                          \n                        else\n                            views.layout_image.setVisibility(8)\n                        end\n                        LuaImageLoader.loadWithRadius(views.iv_avatar,16,item.avatar)\n                        views.tv_title.setText(item.title or 'ERROR TITLE')\n                        views.tv_author.setText(item.author or '')\n                        views.tv_time.setText(item.time or '')\n                        views.tv_comment_count.setText(item.commentCount .. ' 回复')\n                    end\n                    if position == #data then getData(params, data, adapter, fragment, ids.swipe_layout) end\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    launchDetail(fragment, data[position + 1])\n                end,\n            }))\n            ids.swipe_layout.setRefreshing(true)\n            ids.swipe_layout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    getData(params, data, adapter, fragment, ids.swipe_layout, true)\n                end\n            }))\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/tieba/info.json",
    "content": "{\n  \"id\": \"pub.hanks.tieba\",\n  \"name\": \"贴吧\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b0884c77a94448?w=150&h=150&f=png&s=1838\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.4\",\n  \"versionCode\": 6,\n  \"desc\": \"贴吧\"\n}\n"
  },
  {
    "path": "lua/tieba/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"pub.hydrogen.android.R\"\nimport \"android.net.Uri\"\n\nlocal DialogBuilder = import \"android.app.AlertDialog$Builder\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal fragmentNews = require \"tieba/fragment_news\"\n\nlocal sp = activity.getSharedPreferences('tieba', Context.MODE_PRIVATE)\nlocal CONFIG_SITE = \"sites\"\nactivity.setTheme(R.style.Theme_AppCompat_NoActionBar)\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#ff198ef1\",\n    {\n        Toolbar,\n        background = '#ff198ef1',\n        id = 'toolbar',\n        layout_width = \"match\",\n        layout_height = \"56dp\",\n        titleTextColor = \"#FFFFFF\",\n    },\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#ff198ef1\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\nlocal sites = sp.getString(CONFIG_SITE, \"二次元\")\nif not sites:find('||$') then sites = sites .. '||' end\nfor site in string.gmatch(sites, '(.-)||') do\n    print(site)\n    data.fragments[#data.fragments + 1] = fragmentNews.newInstance(site)\n    data.titles[#data.titles + 1] = site .. '吧'\nend\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    activity.setSupportActionBar(toolbar)\n    activity.setStatusBarColor(0xff198ef1)\n    activity.setTitle('贴吧')\n    toolbar.setNavigationIcon(LuaDrawable.create('tieba/tieba.png'))\n    viewPager.setAdapter(adapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\n    tab.setSelectedTabIndicatorColor(0xffffffff)\n    tab.setTabTextColors(0x88ffffff, 0xffffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n\nfunction onCreateOptionsMenu(menu)\n    menu.add(\"网页版\")\n    menu.add(\"管理站点\")\n    return true\nend\n\nlocal layout_intput = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = 'match',\n    paddingBottom = '8dp',\n    paddingRight = '8dp',\n    {\n        EditText,\n        id = 'et',\n        layout_margin = '16dp',\n        layout_width = 'match',\n    },\n    {\n        TextView,\n        id = \"insert_\",\n        text = \"点我插入 || \",\n        textSize = \"13sp\",\n        textColor = \"#888888\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"16dp\",\n        layout_height = \"48dp\",\n        background = \"#11888888\",\n        layout_marginLeft = \"20dp\",        \n        gravity = \"center\",\n    },\n}\n\nlocal function manageSites()\n    local ids = {}\n    local view = loadlayout(layout_intput, ids, ViewGroup)\n    ids.et.setText(sp.getString(CONFIG_SITE, '二次元'))\n    ids.insert_.onClick = function() \n        ids.et.append(\"||\")\n    end\n    DialogBuilder(activity).setTitle('多个贴吧之间用 || 分隔').setView(view).setNegativeButton('取消', nil).setPositiveButton('确定', luajava.createProxy('android.content.DialogInterface$OnClickListener', {\n        onClick = function(dialog, which)\n            local txt = ids.et.getText().toString()\n            sp.edit().putString(CONFIG_SITE, txt).apply()\n            activity.toast('保存成功，下次进入生效')\n        end\n    })).show()\nend\n\nfunction onOptionsItemSelected(item)\n    local title = item.getTitle()\n    if title == \"网页版\" then\n        activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse('http://c.tieba.baidu.com')))\n    end\n    if title == \"管理站点\" then\n        manageSites()\n    end\nend"
  },
  {
    "path": "lua/tv005/activity_agc_detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nlocal uihelper = require \"uihelper\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#fffb7299\",\n    {\n        LinearLayout,\n        orientation = \"horizontal\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#fffb7299\",\n        gravity = \"center_vertical\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginLeft = \"8dp\",\n            scaleType = \"centerInside\",\n            src = \"@drawable/ic_menu_back\",\n        },\n        {\n            TextView,\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            singleLine = true,\n            textIsSelectable = true,\n            ellipsize = \"end\",\n            id = \"tv_title\",\n            gravity = \"center_vertical\",\n            paddingLeft = \"8dp\",\n            textColor = \"#ffffff\",\n            textSize = \"16sp\",\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            LuaWebView,\n            id = \"webview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal css = [[\n    video{width:100%}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-webkit-text-size-adjust:100%}body{font-family:'Helvetica Neue',Helvetica,Arial,Sans-serif;background:#fff;padding-top:0;margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0}h1,h2,h3,h4,h5,h6{font-size:16px}abbr[title]{border-bottom:1px dotted}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:\\201C\\201D\\2018\\2019}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0;vertical-align:middle;color:transparent;font-size:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}table{border-collapse:collapse;border-spacing:0;overflow:hidden}a{text-decoration:none}blockquote{border-left:3px solid #d0e5f2;font-style:normal;display:block;vertical-align:baseline;font-size:100%;margin:.5em 0;padding:0 0 0 1em}ul,ol{padding-left:20px}.content{color:#444;line-height:1.6em;font-size:16px;margin:16px}.content img{max-width:100%;display:block;margin:30px auto}.content img+img{margin-top:15px}.content img[src*=\"zhihu.com/equation\"]{display:inline-block;margin:0 3px}.content a{color:#259}.content a:hover{text-decoration:underline}\n]]\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html>\n<head>\n\t<title></title>\n\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t<style type=\"text/css\">\t%s </style>\n</head>\n<body>\n\n<div class=\"content\"> %s </div>\n<script type=\"text/javascript\">\nfunction openImgActivity(a,b){var c=JSON.stringify({currentIndex:b,uris:a});var d=\"hydrogen://pub.hydrogen.android?action=open_img&data=\"+c;var e=document.createElement(\"iframe\");e.src=d;e.style.display=\"none\";document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},2000)}function init(){var a=document.querySelectorAll(\".content img\");for(var b=0;b<a.length;b++){a[b].addEventListener(\"click\",function(g){var e=g.target||g.srcElement;var c=[];var d=0;var h=document.querySelectorAll(\".content img\");for(var f=0;f<h.length;f++){c[f]=h[f].getAttribute(\"src\");if(e.getAttribute(\"src\").indexOf(c[f])!=-1){d=f}}openImgActivity(c,d)})}}init();\n</script>\n</body>\n</html>\n]]\n\nfunction html_unescape(s)\n    return s:gsub(\"&lt;\", \"<\"):gsub(\"&gt;\", \">\"):gsub(\"&amp;\", \"&\"):gsub(\"&quot;\", '\"'):gsub(\"&#39;\", \"'\"):gsub(\"&#47;\", \"/\")\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0xfffb7299)\n    activity.setContentView(loadlayout(layout))\n    back.onClick = function()\n        activity.finish()\n    end\n    local url = activity.getIntent().getStringExtra('url')\n    tv_title.setText(url)\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local content = string.match(body, '(<div class=\"articleContent\".-)<div class=\"h20 xs[-]hide\">'):gsub('style=\".-\"', ''):gsub('width=\".-\"', ''):gsub('height=\".-\"', '')\n        local data = string.format(htmlTemplate, css, html_unescape(content))\n        uihelper.runOnUiThread(activity, function()\n            --print(data)\n            webview.loadData(data, \"text/html; charset=UTF-8\", nil)\n        end)\n    end)\nend\n\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend\n"
  },
  {
    "path": "lua/tv005/fragment_agc_news.lua",
    "content": "import \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.widget.webview.WebViewActivity\"\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\n\nlocal function fetchData(baseUrl, data, adapter, fragment)\n    local url = string.format(baseUrl, data.page)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        if error or code ~= 200 then\n            print(\"fetchData error : \" .. url)\n            return\n        end\n        local news = {}\n        for v in string.gmatch(body, '<li>(.-)</li>') do\n            local url = string.match(v, '<a href=\"(.-)\" class=\"img fl xs[-]100\" target=\"_blank\">')\n            local imgUrl = string.match(v, '<a.-class=\"img fl xs[-]100\".-<img src=\"(.-)\"/>')\n            local title = string.match(v, '<h3>.-target=\"_blank\">(.-)</a>')\n            local time = string.match(v, '<span class=\"fr time\">(.-)</span>')\n            -- local desc = string.match(v,'<div class=\"p[-]row\">(.-)</div>')\n            if url and imgUrl and time then\n                title = title:gsub(\"%s+\", \"\")\n                time = time:gsub(\"%s+\", \"\")\n                news[#news + 1] = {\n                    title = title,\n                    time = time,\n                    url = url,\n                    imgUrl = imgUrl\n                }\n            end\n        end\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            for i = 1, #news do\n                data.news[#data.news + 1] = news[i]\n            end\n            data.page = data.page + 1\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nfunction launchDetail(fragment, item)\n    local activity = fragment.getActivity()\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'tv005/activity_agc_detail.lua')\n    intent.putExtra(\"url\", '' .. item.url)\n    activity.startActivity(intent)\nend\n\nfunction newInstance(baseUrl)\n\n    local layout = {\n        ListView,\n        id = \"listview\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    }\n\n    local item_view = {\n        RelativeLayout,\n        layout_width = \"fill\",\n        layout_height = \"wrap\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"12dp\",\n        paddingTop = \"16dp\",\n        paddingBottom = \"16dp\",\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_alignParentRight = true,\n            layout_width = \"100dp\",\n            layout_height = \"75dp\",\n            scaleType = \"centerCrop\",\n        },\n        {\n            TextView,\n            id = \"tv_title\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            maxLines = \"2\",\n            layout_alignParentLeft = true,\n            lineSpacingMultiplier = '1.3',\n            textSize = \"14sp\",\n            textColor = \"#222222\",\n            layout_toLeftOf = \"iv_image\",\n        },\n        {\n            TextView,\n            id = \"tv_time\",\n            layout_width = \"120dp\",\n            paddingRight = \"16dp\",\n            layout_alignParentLeft = true,\n            layout_alignParentBottom = true,\n            textSize = \"12sp\",\n            textColor = \"#aaaaaa\",\n            layout_toLeftOf = \"iv_image\",\n        },\n    }\n\n    local data = {\n        page = 1,\n        news = {}\n    }\n\n    local ids = {}\n    local fragment = LuaFragment.newInstance()\n    local adapter\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data.news end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if position == #data.news then\n                        fetchData(baseUrl, data, adapter, fragment)\n                    end\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        convertView.getLayoutParams().width = parent.getWidth()\n                        convertView.setTag(views)\n                    end\n                    local views = convertView.getTag()\n                    local item = data.news[position]\n                    if item.imgUrl then\n                        views.iv_image.setVisibility(0)\n                        LuaImageLoader.load(views.iv_image, item.imgUrl)\n                    else views.iv_image.setVisibility(8)\n                    end\n                    views.tv_title.setText(item.title)\n                    views.tv_time.setText(item.time)\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    launchDetail(fragment, data.news[position + 1])\n                end,\n            }))\n            fetchData(baseUrl, data, adapter, fragment) -- getdata may call ther lua files\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/tv005/info.json",
    "content": "{\n  \"id\": \"pub.hanks.tv005\",\n  \"name\": \"动漫资讯\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b0885388e77ef8?w=150&h=150&f=png&s=2567\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.2\",\n  \"versionCode\": 4,\n  \"desc\": \"动漫新闻，cosplay，005.tv\"\n}\n"
  },
  {
    "path": "lua/tv005/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A agc news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\n\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\n\nlocal fragmentNews = require \"tv005/fragment_agc_news\"\n\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#fb7299\",\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#fffb7299\",\n    },\n    {\n        FrameLayout,\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    },\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\ntable.insert(data.fragments, fragmentNews.newInstance(\"http://www.005.tv/zx/list_526_%s.html\"))\ntable.insert(data.titles, '二次元资讯')\n\ntable.insert(data.fragments, fragmentNews.newInstance(\"http://www.005.tv/zwh/list_519_%s.html\"))\ntable.insert(data.titles, '慢慢说')\n\ntable.insert(data.fragments, fragmentNews.newInstance(\"http://www.005.tv/Cosplay/list_522_%s.html\"))\ntable.insert(data.titles, 'cos本子图')\n\ntable.insert(data.fragments, fragmentNews.newInstance(\"http://www.005.tv/zh/list_524_%s.html\"))\ntable.insert(data.titles, '展会资讯')\n\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    viewPager.setAdapter(adapter)\n    tab.setSelectedTabIndicatorColor(0xffffffff)\n    tab.setTabTextColors(0x88ffffff, 0xffffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n"
  },
  {
    "path": "lua/weather/city.lua",
    "content": "local China = {\n    ['北京'] = {\n        ['北京'] = { _101010700 = '昌平', _101011400 = '门头沟', _101011000 = '石景山', _101010900 = '丰台', _101010300 = '朝阳', _101010100 = '北京', _101010800 = '延庆', _101011300 = '密云', _101010600 = '通州', _101011100 = '大兴', _101011200 = '房山', _101010400 = '顺义', _101010200 = '海淀', _101010500 = '怀柔', _101011500 = '平谷', },\n    },\n    ['上海'] = {\n        ['上海'] = { _101021000 = '奉贤', _101020100 = '上海', _101020800 = '青浦', _101020700 = '金山', _101021200 = '徐汇', _101020500 = '嘉定', _101020600 = '浦东新区', _101020900 = '松江', _101021100 = '崇明', _101020300 = '宝山', _101020200 = '闵行', },\n    },\n    ['天津'] = {\n        ['天津'] = { _101031400 = '蓟县', _101030300 = '宝坻', _101030500 = '西青', _101031000 = '津南', _101030100 = '天津', _101030700 = '宁河', _101030600 = '北辰', _101030200 = '武清', _101031100 = '滨海新区', _101030900 = '静海', _101030400 = '东丽', },\n    },\n    ['湖南'] = {\n        ['益阳'] = { _101250701 = '赫山区', _101250702 = '南县', _101250705 = '沅江', _101250700 = '益阳', _101250704 = '安化', _101250703 = '桃江', },\n        ['邵阳'] = { _101250901 = '邵阳', _101250902 = '隆回', _101250908 = '武冈', _101250909 = '城步', _101250905 = '邵东', _101250906 = '绥宁', _101250907 = '新宁', _101250910 = '邵阳县', _101250903 = '洞口', _101250904 = '新邵', },\n        ['郴州'] = { _101250509 = '安仁', _101250510 = '永兴', _101250501 = '郴州', _101250507 = '资兴', _101250502 = '桂阳', _101250505 = '临武', _101250512 = '苏仙', _101250504 = '宜章', _101250511 = '桂东', _101250508 = '汝城', _101250503 = '嘉禾', },\n        ['常德'] = { _101250607 = '石门', _101250608 = '津市', _101250605 = '澧县', _101250603 = '桃源', _101250606 = '临澧', _101250601 = '常德', _101250604 = '汉寿', _101250602 = '安乡', },\n        ['湘西'] = { _101251508 = '花垣', _101251506 = '泸溪', _101251504 = '古丈', _101251502 = '保靖', _101251507 = '龙山', _101251503 = '永顺', _101251505 = '凤凰', _101251501 = '吉首', },\n        ['长沙'] = { _101250102 = '宁乡', _101250104 = '湘江新区', _101250105 = '望城', _101250103 = '浏阳', _101250106 = '长沙县', _101250101 = '长沙', },\n        ['怀化'] = { _101251204 = '辰溪', _101251203 = '沅陵', _101251208 = '麻阳', _101251211 = '溆浦', _101251207 = '通道', _101251210 = '芷江', _101251209 = '新晃', _101251212 = '中方', _101251206 = '会同', _101251213 = '洪江', _101251205 = '靖州', _101251201 = '怀化', },\n        ['株洲'] = { _101250301 = '株洲', _101250303 = '醴陵', _101250305 = '茶陵', _101250302 = '攸县', _101250306 = '炎陵', },\n        ['湘潭'] = { _101250203 = '湘乡', _101250201 = '湘潭', _101250202 = '韶山', },\n        ['衡阳'] = { _101250409 = '南岳', _101250404 = '祁东', _101250402 = '衡山', _101250405 = '衡阳县', _101250407 = '衡南', _101250401 = '衡阳', _101250406 = '常宁', _101250403 = '衡东', _101250408 = '耒阳', },\n        ['永州'] = { _101251409 = '新田', _101251411 = '冷水滩', _101251406 = '宁远', _101251410 = '江华', _101251408 = '蓝山', _101251407 = '江永', _101251404 = '双牌', _101251401 = '永州', _101251403 = '东安', _101251402 = '祁阳', _101251405 = '道县', },\n        ['娄底'] = { _101250801 = '娄底', _101250802 = '双峰', _101250806 = '涟源', _101250805 = '新化', _101250803 = '冷水江', },\n        ['岳阳'] = { _101251002 = '华容', _101251003 = '湘阴', _101251004 = '汨罗', _101251006 = '临湘', _101251001 = '岳阳', _101251005 = '平江', },\n        ['张家界'] = { _101251103 = '慈利', _101251102 = '桑植', _101251104 = '武陵源', _101251101 = '张家界', },\n    },\n    ['浙江'] = {\n        ['嘉兴'] = { _101210301 = '嘉兴', _101210306 = '海盐', _101210305 = '平湖', _101210302 = '嘉善', _101210303 = '海宁', _101210304 = '桐乡', },\n        ['宁波'] = { _101210404 = '余姚', _101210401 = '宁波', _101210410 = '北仑', _101210408 = '宁海', _101210405 = '奉化', _101210403 = '慈溪', _101210412 = '镇海', _101210411 = '鄞州', _101210406 = '象山', },\n        ['杭州'] = { _101210104 = '淳安', _101210102 = '萧山', _101210105 = '建德', _101210103 = '桐庐', _101210107 = '临安', _101210106 = '余杭', _101210108 = '富阳', _101210101 = '杭州', },\n        ['舟山'] = { _101211104 = '岱山', _101211105 = '普陀', _101211106 = '定海', _101211102 = '嵊泗', _101211101 = '舟山', },\n        ['台州'] = { _101210609 = '洪家', _101210603 = '玉环', _101210607 = '温岭', _101210605 = '天台', _101210601 = '台州', _101210604 = '三门', _101210610 = '临海', _101210606 = '仙居', _101210612 = '黄岩', _101210611 = '椒江', _101210613 = '路桥', },\n        ['温州'] = { _101210709 = '苍南', _101210705 = '瑞安', _101210708 = '永嘉', _101210704 = '平阳', _101210701 = '温州', _101210707 = '乐清', _101210702 = '泰顺', _101210703 = '文成', _101210706 = '洞头', },\n        ['绍兴'] = { _101210501 = '越城', _101210504 = '新昌', _101210502 = '诸暨', _101210506 = '柯桥', _101210503 = '上虞', _101210505 = '嵊州', },\n        ['丽水'] = { _101210806 = '云和', _101210808 = '松阳', _101210804 = '缙云', _101210803 = '龙泉', _101210807 = '庆元', _101210802 = '遂昌', _101210801 = '丽水', _101210809 = '景宁', _101210805 = '青田', },\n        ['湖州'] = { _101210204 = '德清', _101210201 = '湖州', _101210203 = '安吉', _101210202 = '长兴', },\n        ['金华'] = { _101210908 = '磐安', _101210903 = '兰溪', _101210907 = '永康', _101210906 = '武义', _101210902 = '浦江', _101210904 = '义乌', _101210901 = '金华', _101210905 = '东阳', },\n        ['衢州'] = { _101211006 = '衢江', _101211003 = '开化', _101211002 = '常山', _101211005 = '江山', _101211004 = '龙游', _101211001 = '衢州', },\n    },\n    ['海南'] = {\n        ['三亚'] = { _101310201 = '三亚', },\n        ['东方'] = { _101310202 = '东方', },\n        ['西沙'] = { _101310217 = '西沙', },\n        ['海口'] = { _101310101 = '海口', },\n        ['定安'] = { _101310209 = '定安', },\n        ['屯昌'] = { _101310210 = '屯昌', },\n        ['南沙'] = { _101310220 = '南沙', },\n        ['陵水'] = { _101310216 = '陵水', },\n        ['五指山'] = { _101310222 = '五指山', },\n        ['临高'] = { _101310203 = '临高', },\n        ['中沙'] = { _101310224 = '中沙', },\n        ['儋州'] = { _101310205 = '儋州', },\n        ['乐东'] = { _101310221 = '乐东', },\n        ['文昌'] = { _101310212 = '文昌', },\n        ['万宁'] = { _101310215 = '万宁', },\n        ['琼海'] = { _101310211 = '琼海', },\n        ['琼中'] = { _101310208 = '琼中', },\n        ['澄迈'] = { _101310204 = '澄迈', },\n        ['保亭'] = { _101310214 = '保亭', },\n        ['昌江'] = { _101310206 = '昌江', },\n        ['白沙'] = { _101310207 = '白沙', },\n    },\n    ['青海'] = {\n        ['西宁'] = { _101150102 = '大通', _101150103 = '湟源', _101150104 = '湟中', _101150101 = '西宁', },\n        ['海北'] = { _101150802 = '门源', _101150801 = '海北', _101150806 = '刚察', _101150803 = '祁连', },\n        ['海西'] = { _101150714 = '格尔木', _101150708 = '天峻', _101150713 = '大柴旦', _101150701 = '德令哈', _101150716 = '冷湖', _101150709 = '乌兰', _101150712 = '茫崖', _101150715 = '都兰', },\n        ['海东'] = { _101150206 = '循化', _101150201 = '平安', _101150205 = '化隆', _101150204 = '互助', _101150202 = '乐都', _101150203 = '民和', },\n        ['玉树'] = { _101150605 = '囊谦', _101150604 = '杂多', _101150601 = '玉树', _101150606 = '曲麻莱', _101150603 = '治多', _101150602 = '称多', },\n        ['海南'] = { _101150406 = '兴海', _101150401 = '共和', _101150408 = '同德', _101150407 = '贵南', _101150404 = '贵德', },\n        ['果洛'] = { _101150501 = '玛沁', _101150503 = '甘德', _101150506 = '玛多', _101150504 = '达日', _101150502 = '班玛', _101150505 = '久治', },\n        ['黄南'] = { _101150304 = '河南', _101150301 = '同仁', _101150303 = '泽库', _101150302 = '尖扎', },\n    },\n    ['湖北'] = {\n        ['仙桃'] = { _101201601 = '仙桃', },\n        ['恩施'] = { _101201007 = '来凤', _101201001 = '恩施', _101201003 = '建始', _101201005 = '宣恩', _101201008 = '巴东', _101201004 = '咸丰', _101201002 = '利川', _101201006 = '鹤峰', },\n        ['武汉'] = { _101200104 = '新洲', _101200102 = '蔡甸', _101200101 = '武汉', _101200106 = '东西湖', _101200105 = '江夏', _101200103 = '黄陂', },\n        ['鄂州'] = { _101200301 = '鄂州', _101200302 = '梁子湖', },\n        ['宜昌'] = { _101200902 = '远安', _101200903 = '秭归', _101200908 = '长阳', _101200909 = '宜都', _101200912 = '夷陵', _101200910 = '枝江', _101200904 = '兴山', _101200911 = '三峡', _101200906 = '五峰', _101200907 = '当阳', _101200901 = '宜昌', },\n        ['随州'] = { _101201301 = '随州', _101201302 = '广水', },\n        ['黄石'] = { _101200604 = '铁山', _101200601 = '黄石', _101200602 = '大冶', _101200603 = '阳新', _101200606 = '西塞山', _101200605 = '下陆', },\n        ['孝感'] = { _101200404 = '大悟', _101200402 = '安陆', _101200405 = '应城', _101200401 = '孝感', _101200406 = '汉川', _101200407 = '孝昌', _101200403 = '云梦', },\n        ['襄阳'] = { _101200204 = '南漳', _101200202 = '襄州', _101200203 = '保康', _101200208 = '枣阳', _101200205 = '宜城', _101200206 = '老河口', _101200207 = '谷城', _101200201 = '襄阳', },\n        ['天门'] = { _101201501 = '天门', },\n        ['潜江'] = { _101201701 = '潜江', },\n        ['咸宁'] = { _101200703 = '嘉鱼', _101200701 = '咸宁', _101200702 = '赤壁', _101200705 = '通城', _101200704 = '崇阳', _101200706 = '通山', },\n        ['神农架'] = { _101201201 = '神农架', },\n        ['十堰'] = { _101201104 = '郧阳', _101201109 = '张湾', _101201106 = '房县', _101201107 = '丹江口', _101201105 = '竹山', _101201102 = '竹溪', _101201108 = '茅箭', _101201103 = '郧西', _101201101 = '十堰', },\n        ['黄冈'] = { _101200508 = '黄梅', _101200502 = '红安', _101200506 = '浠水', _101200505 = '英山', _101200510 = '团风', _101200509 = '武穴', _101200507 = '蕲春', _101200503 = '麻城', _101200501 = '黄冈', _101200504 = '罗田', },\n        ['荆州'] = { _101200807 = '松滋', _101200801 = '荆州', _101200808 = '沙市', _101200804 = '石首', _101200806 = '洪湖', _101200805 = '监利', _101200803 = '公安', _101200802 = '江陵', },\n        ['荆门'] = { _101201403 = '京山', _101201404 = '掇刀', _101201405 = '沙洋', _101201402 = '钟祥', _101201401 = '荆门', },\n    },\n    ['新疆'] = {\n        ['伊犁'] = { _101131002 = '察布查尔', _101131004 = '伊宁县', _101131010 = '霍尔果斯', _101131001 = '伊宁', _101131003 = '尼勒克', _101131008 = '特克斯', _101131011 = '奎屯', _101131007 = '昭苏', _101131006 = '新源', _101131005 = '巩留', _101131009 = '霍城', },\n        ['石河子'] = { _101130303 = '莫索湾', _101130301 = '石河子', _101130302 = '炮台', },\n        ['和田'] = { _101131306 = '民丰', _101131301 = '和田', _101131302 = '皮山', _101131307 = '于田', _101131304 = '墨玉', _101131305 = '洛浦', _101131303 = '策勒', },\n        ['克州'] = { _101131503 = '阿克陶', _101131502 = '乌恰', _101131501 = '阿图什', _101131504 = '阿合奇', },\n        ['克拉玛依'] = { _101130202 = '乌尔禾', _101130203 = '白碱滩', _101130201 = '克拉玛依', },\n        ['阿克苏'] = { _101130804 = '拜城', _101130809 = '阿瓦提', _101130802 = '乌什', _101130806 = '沙雅', _101130807 = '库车', _101130801 = '阿克苏', _101130805 = '新和', _101130803 = '温宿', _101130808 = '柯坪', },\n        ['博尔塔拉'] = { _101131606 = '阿拉山口', _101131601 = '博乐', _101131603 = '精河', _101131602 = '温泉', },\n        ['阿拉尔'] = { _101130701 = '阿拉尔', },\n        ['吐鲁番'] = { _101130502 = '托克逊', _101130504 = '鄯善', _101130501 = '吐鲁番', },\n        ['哈密'] = { _101131203 = '巴里坤', _101131201 = '哈密', _101131204 = '伊吾', },\n        ['昌吉'] = { _101130405 = '吉木萨尔', _101130403 = '米泉', _101130404 = '阜康', _101130401 = '昌吉', _101130406 = '奇台', _101130409 = '蔡家湖', _101130408 = '木垒', _101130402 = '呼图壁', _101130407 = '玛纳斯', },\n        ['阿勒泰'] = { _101131407 = '福海', _101131409 = '青河', _101131401 = '阿勒泰', _101131408 = '富蕴', _101131402 = '哈巴河', _101131406 = '布尔津', _101131405 = '吉木乃', },\n        ['塔城'] = { _101131103 = '额敏', _101131105 = '托里', _101131102 = '裕民', _101131101 = '塔城', _101131107 = '沙湾', _101131106 = '乌苏', _101131104 = '和布克赛尔', },\n        ['巴音郭楞'] = { _101130603 = '尉犁', _101130606 = '和静', _101130611 = '铁干里克', _101130613 = '塔中', _101130601 = '库尔勒', _101130608 = '和硕', _101130610 = '巴音布鲁克', _101130612 = '博湖', _101130604 = '若羌', _101130607 = '焉耆', _101130605 = '且末', _101130602 = '轮台', _101130614 = '巴仑台', },\n        ['乌鲁木齐'] = { _101130103 = '小渠子', _101130109 = '天池', _101130108 = '乌鲁木齐牧试站', _101130110 = '白杨沟', _101130101 = '乌鲁木齐', _101130105 = '达坂城', },\n        ['喀什'] = { _101130905 = '莎车', _101130907 = '泽普', _101130912 = '疏勒', _101130911 = '疏附', _101130910 = '伽师', _101130906 = '叶城', _101130909 = '岳普湖', _101130903 = '塔什库尔干', _101130908 = '巴楚', _101130902 = '英吉沙', _101130904 = '麦盖提', _101130901 = '喀什', },\n    },\n    ['宁夏'] = {\n        ['吴忠'] = { _101170306 = '青铜峡', _101170302 = '同心', _101170301 = '吴忠', _101170303 = '盐池', },\n        ['固原'] = { _101170403 = '隆德', _101170404 = '泾源', _101170401 = '固原', _101170402 = '西吉', _101170406 = '彭阳', },\n        ['银川'] = { _101170101 = '银川', _101170104 = '贺兰', _101170103 = '灵武', _101170102 = '永宁', },\n        ['中卫'] = { _101170501 = '中卫', _101170504 = '海原', _101170502 = '中宁', },\n        ['石嘴山'] = { _101170204 = '陶乐', _101170203 = '平罗', _101170201 = '石嘴山', _101170202 = '惠农', },\n    },\n    ['西藏'] = {\n        ['林芝'] = { _101140401 = '林芝', _101140403 = '米林', _101140406 = '朗县', _101140402 = '波密', _101140405 = '工布江达', _101140407 = '墨脱', _101140404 = '察隅', },\n        ['拉萨'] = { _101140108 = '墨竹工卡', _101140101 = '拉萨', _101140107 = '达孜', _101140103 = '尼木', _101140106 = '曲水', _101140102 = '当雄', _101140104 = '林周', _101140105 = '堆龙德庆', },\n        ['山南'] = { _101140314 = '曲松', _101140313 = '琼结', _101140309 = '乃东', _101140306 = '错那', _101140304 = '加查', _101140305 = '浪卡子', _101140310 = '桑日', _101140312 = '措美', _101140301 = '山南', _101140303 = '扎囊', _101140307 = '隆子', _101140311 = '洛扎', _101140308 = '泽当', _101140302 = '贡嘎', },\n        ['日喀则'] = { _101140209 = '萨嘎', _101140202 = '拉孜', _101140212 = '定结', _101140217 = '白朗', _101140203 = '南木林', _101140207 = '帕里', _101140204 = '聂拉木', _101140201 = '日喀则', _101140210 = '吉隆', _101140205 = '定日', _101140220 = '仁布', _101140211 = '昂仁', _101140219 = '康马', _101140218 = '亚东', _101140216 = '岗巴', _101140214 = '谢通门', _101140208 = '仲巴', _101140206 = '江孜', _101140213 = '萨迦', },\n        ['昌都'] = { _101140510 = '察雅', _101140502 = '丁青', _101140511 = '贡觉', _101140509 = '江达', _101140508 = '八宿', _101140505 = '左贡', _101140507 = '类乌齐', _101140503 = '边坝', _101140501 = '昌都', _101140504 = '洛隆', _101140506 = '芒康', },\n        ['阿里'] = { _101140706 = '札达', _101140702 = '改则', _101140709 = '革吉', _101140705 = '普兰', _101140707 = '噶尔', _101140708 = '日土', _101140701 = '阿里', _101140704 = '狮泉河', _101140710 = '措勤', _101140703 = '申扎', },\n        ['那曲'] = { _101140605 = '安多', _101140606 = '索县', _101140602 = '尼玛', _101140601 = '那曲', _101140603 = '嘉黎', _101140607 = '聂荣', _101140610 = '双湖', _101140609 = '比如', _101140608 = '巴青', _101140604 = '班戈', },\n    },\n    ['吉林'] = {\n        ['延边'] = { _101060307 = '龙井', _101060304 = '汪清', _101060309 = '图们', _101060308 = '珲春', _101060305 = '和龙', _101060302 = '敦化', _101060301 = '延吉', _101060303 = '安图', },\n        ['吉林'] = { _101060204 = '蛟河', _101060201 = '吉林', _101060202 = '舒兰', _101060203 = '永吉', _101060205 = '磐石', _101060206 = '桦甸', },\n        ['白山'] = { _101060902 = '靖宇', _101060904 = '东岗', _101060905 = '长白', _101060901 = '白山', _101060903 = '临江', _101060906 = '抚松', _101060907 = '江源', },\n        ['白城'] = { _101060604 = '镇赉', _101060602 = '洮南', _101060605 = '通榆', _101060603 = '大安', _101060601 = '白城', },\n        ['四平'] = { _101060401 = '四平', _101060405 = '伊通', _101060403 = '梨树', _101060404 = '公主岭', _101060402 = '双辽', },\n        ['长春'] = { _101060104 = '九台', _101060107 = '二道', _101060101 = '长春', _101060102 = '农安', _101060103 = '德惠', _101060106 = '双阳', _101060105 = '榆树', },\n        ['通化'] = { _101060506 = '通化县', _101060501 = '通化', _101060502 = '梅河口', _101060504 = '辉南', _101060505 = '集安', _101060503 = '柳河', },\n        ['松原'] = { _101060805 = '扶余', _101060804 = '长岭', _101060803 = '前郭', _101060801 = '松原', _101060802 = '乾安', },\n        ['辽源'] = { _101060702 = '东丰', _101060703 = '东辽', _101060701 = '辽源', },\n    },\n    ['江西'] = {\n        ['赣州'] = { _101240716 = '寻乌', _101240712 = '安远', _101240710 = '于都', _101240705 = '大余', _101240713 = '全南', _101240701 = '赣州', _101240704 = '南康', _101240707 = '宁都', _101240709 = '瑞金', _101240706 = '信丰', _101240715 = '定南', _101240711 = '会昌', _101240708 = '石城', _101240717 = '兴国', _101240703 = '上犹', _101240714 = '龙南', _101240718 = '赣县', _101240702 = '崇义', },\n        ['新余'] = { _101241002 = '分宜', _101241001 = '新余', },\n        ['吉安'] = { _101240609 = '万安', _101240601 = '吉安', _101240612 = '安福', _101240602 = '吉安县', _101240611 = '泰和', _101240603 = '吉水', _101240607 = '永新', _101240605 = '峡江', _101240608 = '井冈山', _101240613 = '宁冈', _101240606 = '永丰', _101240610 = '遂川', _101240604 = '新干', },\n        ['九江'] = { _101240204 = '武宁', _101240208 = '彭泽', _101240202 = '瑞昌', _101240201 = '九江', _101240205 = '德安', _101240206 = '永修', _101240212 = '修水', _101240210 = '都昌', _101240209 = '星子', _101240203 = '庐山', _101240207 = '湖口', },\n        ['萍乡'] = { _101240903 = '上栗', _101240904 = '安源', _101240902 = '莲花', _101240905 = '芦溪', _101240906 = '湘东', _101240901 = '萍乡', },\n        ['南昌'] = { _101240101 = '南昌', _101240102 = '新建', _101240103 = '南昌县', _101240104 = '安义', _101240105 = '进贤', },\n        ['宜春'] = { _101240509 = '樟树', _101240510 = '丰城', _101240506 = '靖安', _101240507 = '奉新', _101240503 = '宜丰', _101240504 = '万载', _101240502 = '铜鼓', _101240508 = '高安', _101240501 = '宜春', _101240505 = '上高', },\n        ['抚州'] = { _101240407 = '宜黄', _101240405 = '金溪', _101240411 = '东乡', _101240408 = '南城', _101240406 = '资溪', _101240410 = '黎川', _101240409 = '南丰', _101240401 = '抚州', _101240404 = '崇仁', _101240402 = '广昌', _101240403 = '乐安', },\n        ['鹰潭'] = { _101241102 = '余江', _101241101 = '鹰潭', _101241103 = '贵溪', },\n        ['景德镇'] = { _101240801 = '景德镇', _101240802 = '乐平', _101240803 = '浮梁', },\n        ['上饶'] = { _101240310 = '横峰', _101240307 = '德兴', _101240309 = '弋阳', _101240302 = '鄱阳', _101240306 = '万年', _101240308 = '上饶县', _101240313 = '广丰', _101240301 = '上饶', _101240312 = '玉山', _101240303 = '婺源', _101240311 = '铅山', _101240305 = '余干', },\n    },\n    ['广东'] = {\n        ['汕尾'] = { _101282101 = '汕尾', _101282102 = '海丰', _101282104 = '陆河', _101282103 = '陆丰', },\n        ['佛山'] = { _101280800 = '佛山', _101280801 = '顺德', _101280803 = '南海', _101280802 = '三水', _101280804 = '高明', },\n        ['惠州'] = { _101280305 = '龙门', _101280304 = '惠东', _101280302 = '博罗', _101280301 = '惠州', _101280303 = '惠阳', },\n        ['揭阳'] = { _101281904 = '惠来', _101281902 = '揭西', _101281905 = '揭东', _101281903 = '普宁', _101281901 = '揭阳', },\n        ['肇庆'] = { _101280901 = '肇庆', _101280908 = '高要', _101280906 = '怀集', _101280907 = '封开', _101280905 = '德庆', _101280902 = '广宁', _101280903 = '四会', },\n        ['阳江'] = { _101281804 = '阳西', _101281801 = '阳江', _101281802 = '阳春', _101281803 = '阳东', },\n        ['茂名'] = { _101282003 = '化州', _101282002 = '高州', _101282001 = '茂名', _101282004 = '电白', _101282005 = '信宜', _101282006 = '茂港', },\n        ['清远'] = { _101281308 = '清新', _101281307 = '英德', _101281301 = '清远', _101281303 = '连州', _101281302 = '连南', _101281304 = '连山', _101281306 = '佛冈', _101281305 = '阳山', },\n        ['汕头'] = { _101280502 = '潮阳', _101280504 = '南澳', _101280503 = '澄海', _101280501 = '汕头', },\n        ['梅州'] = { _101280401 = '梅州', _101280404 = '大埔', _101280407 = '平远', _101280409 = '梅县', _101280408 = '五华', _101280406 = '丰顺', _101280403 = '蕉岭', _101280402 = '兴宁', },\n        ['云浮'] = { _101281401 = '云浮', _101281403 = '新兴', _101281406 = '云安', _101281402 = '罗定', _101281404 = '郁南', },\n        ['湛江'] = { _101281004 = '徐闻', _101281001 = '湛江', _101281002 = '吴川', _101281005 = '廉江', _101281007 = '遂溪', _101281008 = '坡头', _101281006 = '赤坎', _101281003 = '雷州', _101281009 = '霞山', _101281010 = '麻章', },\n        ['潮州'] = { _101281503 = '潮安', _101281501 = '潮州', _101281502 = '饶平', },\n        ['广州'] = { _101280103 = '从化', _101280104 = '增城', _101280102 = '番禺', _101280105 = '花都', _101280101 = '广州', },\n        ['中山'] = { _101281701 = '中山', },\n        ['东莞'] = { _101281601 = '东莞', },\n        ['河源'] = { _101281203 = '连平', _101281206 = '东源', _101281201 = '河源', _101281202 = '紫金', _101281205 = '龙川', _101281204 = '和平', },\n        ['韶关'] = { _101280207 = '南雄', _101280206 = '仁化', _101280209 = '曲江', _101280203 = '始兴', _101280205 = '乐昌', _101280208 = '新丰', _101280204 = '翁源', _101280211 = '武江', _101280201 = '韶关', _101280210 = '浈江', _101280202 = '乳源', },\n        ['江门'] = { _101281109 = '江海', _101281106 = '台山', _101281103 = '开平', _101281108 = '鹤山', _101281104 = '新会', _101281105 = '恩平', _101281107 = '蓬江', _101281101 = '江门', },\n        ['深圳'] = { _101280601 = '深圳', },\n        ['珠海'] = { _101280702 = '斗门', _101280703 = '金湾', _101280701 = '珠海', },\n    },\n    ['安徽'] = {\n        ['池州'] = { _101221703 = '青阳', _101221705 = '石台', _101221704 = '九华山', _101221702 = '东至', _101221701 = '池州', },\n        ['芜湖'] = { _101220301 = '芜湖', _101220304 = '南陵', _101220303 = '芜湖县', _101220302 = '繁昌', _101220305 = '无为', },\n        ['蚌埠'] = { _101220202 = '怀远', _101220204 = '五河', _101220201 = '蚌埠', _101220203 = '固镇', },\n        ['淮北'] = { _101221202 = '濉溪', _101221201 = '淮北', },\n        ['宣城'] = { _101221403 = '旌德', _101221407 = '郎溪', _101221406 = '广德', _101221401 = '宣城', _101221404 = '宁国', _101221402 = '泾县', _101221405 = '绩溪', },\n        ['六安'] = { _101221502 = '霍邱', _101221507 = '舒城', _101221506 = '霍山', _101221501 = '六安', _101221505 = '金寨', _101221503 = '寿县', },\n        ['黄山'] = { _101221007 = '休宁', _101221005 = '黟县', _101221008 = '黄山风景区(光明顶)', _101221002 = '黄山区', _101221006 = '歙县', _101221003 = '屯溪', _101221001 = '黄山', _101221004 = '祁门', },\n        ['淮南'] = { _101220403 = '潘集', _101220402 = '凤台', _101220401 = '淮南', },\n        ['滁州'] = { _101221106 = '来安', _101221102 = '凤阳', _101221105 = '全椒', _101221107 = '天长', _101221101 = '滁州', _101221103 = '明光', _101221104 = '定远', },\n        ['阜阳'] = { _101220806 = '太和', _101220804 = '临泉', _101220802 = '阜南', _101220805 = '界首', _101220801 = '阜阳', _101220803 = '颍上', },\n        ['宿州'] = { _101220701 = '宿州', _101220704 = '泗县', _101220705 = '萧县', _101220703 = '灵璧', _101220702 = '砀山', },\n        ['亳州'] = { _101220903 = '利辛', _101220902 = '涡阳', _101220904 = '蒙城', _101220901 = '亳州', },\n        ['铜陵'] = { _101221301 = '铜陵', },\n        ['合肥'] = { _101220104 = '肥西', _101220102 = '长丰', _101220103 = '肥东', _101220101 = '合肥', _101220105 = '巢湖', _101220106 = '庐江', },\n        ['安庆'] = { _101220608 = '岳西', _101220602 = '枞阳', _101220607 = '望江', _101220609 = '桐城', _101220606 = '宿松', _101220604 = '潜山', _101220603 = '太湖', _101220601 = '安庆', _101220605 = '怀宁', },\n        ['马鞍山'] = { _101220504 = '和县', _101220503 = '含山', _101220502 = '当涂', _101220501 = '马鞍山', },\n    },\n    ['甘肃'] = {\n        ['平凉'] = { _101160308 = '崆峒', _101160301 = '平凉', _101160306 = '庄浪', _101160307 = '静宁', _101160302 = '泾川', _101160304 = '崇信', _101160303 = '灵台', _101160305 = '华亭', },\n        ['庆阳'] = { _101160409 = '庆城', _101160404 = '华池', _101160401 = '庆阳', _101160407 = '宁县', _101160406 = '正宁', _101160408 = '镇原', _101160403 = '环县', _101160405 = '合水', },\n        ['嘉峪关'] = { _101161401 = '嘉峪关', },\n        ['张掖'] = { _101160706 = '山丹', _101160705 = '高台', _101160704 = '临泽', _101160703 = '民乐', _101160702 = '肃南', _101160701 = '张掖', },\n        ['兰州'] = { _101160104 = '榆中', _101160103 = '永登', _101160101 = '兰州', _101160102 = '皋兰', },\n        ['金昌'] = { _101160602 = '永昌', _101160601 = '金昌', },\n        ['陇南'] = { _101161004 = '宕昌', _101161002 = '成县', _101161006 = '西和', _101161008 = '徽县', _101161003 = '文县', _101161005 = '康县', _101161007 = '礼县', _101161009 = '两当', _101161001 = '武都', },\n        ['定西'] = { _101160202 = '通渭', _101160204 = '渭源', _101160208 = '安定', _101160207 = '岷县', _101160203 = '陇西', _101160205 = '临洮', _101160206 = '漳县', _101160201 = '定西', },\n        ['临夏'] = { _101161103 = '永靖', _101161104 = '广河', _101161101 = '临夏', _101161102 = '康乐', _101161106 = '东乡', _101161105 = '和政', _101161107 = '积石山', },\n        ['白银'] = { _101161303 = '会宁', _101161305 = '景泰', _101161301 = '白银', _101161302 = '靖远', _101161304 = '平川', },\n        ['甘南'] = { _101161205 = '迭部', _101161208 = '夏河', _101161207 = '碌曲', _101161203 = '卓尼', _101161201 = '合作', _101161202 = '临潭', _101161204 = '舟曲', _101161206 = '玛曲', },\n        ['天水'] = { _101160905 = '甘谷', _101160907 = '张家川', _101160903 = '清水', _101160908 = '麦积', _101160901 = '天水', _101160906 = '武山', _101160904 = '秦安', },\n        ['酒泉'] = { _101160803 = '金塔', _101160808 = '敦煌', _101160801 = '酒泉', _101160807 = '玉门', _101160806 = '肃北', _101160804 = '阿克塞', _101160805 = '瓜州', },\n        ['武威'] = { _101160503 = '古浪', _101160502 = '民勤', _101160501 = '武威', _101160505 = '天祝', },\n    },\n    ['陕西'] = {\n        ['西安'] = { _101110101 = '西安', _101110107 = '高陵', _101110106 = '户县', _101110103 = '临潼', _101110102 = '长安', _101110104 = '蓝田', _101110105 = '周至', },\n        ['延安'] = { _101110308 = '甘泉', _101110300 = '延安', _101110304 = '宜川', _101110309 = '洛川', _101110302 = '延川', _101110312 = '吴起', _101110311 = '黄龙', _101110307 = '安塞', _101110303 = '子长', _101110306 = '志丹', _101110310 = '黄陵', _101110305 = '富县', _101110301 = '延长', },\n        ['杨凌'] = { _101111101 = '杨凌', },\n        ['榆林'] = { _101110410 = '绥德', _101110412 = '清涧', _101110403 = '神木', _101110413 = '榆阳', _101110404 = '佳县', _101110401 = '榆林', _101110409 = '子洲', _101110411 = '吴堡', _101110408 = '米脂', _101110402 = '府谷', _101110406 = '靖边', _101110405 = '定边', _101110407 = '横山', },\n        ['渭南'] = { _101110508 = '澄城', _101110502 = '华县', _101110504 = '大荔', _101110503 = '潼关', _101110501 = '渭南', _101110511 = '华阴', _101110505 = '白水', _101110510 = '韩城', _101110509 = '合阳', _101110507 = '蒲城', _101110506 = '富平', },\n        ['铜川'] = { _101111002 = '耀县', _101111001 = '铜川', _101111004 = '耀州', _101111003 = '宜君', },\n        ['宝鸡'] = { _101110909 = '太白', _101110911 = '陇县', _101110904 = '麟游', _101110903 = '千阳', _101110906 = '凤翔', _101110901 = '宝鸡', _101110907 = '扶风', _101110910 = '凤县', _101110908 = '眉县', _101110912 = '陈仓', _101110905 = '岐山', },\n        ['安康'] = { _101110707 = '平利', _101110704 = '汉阴', _101110702 = '紫阳', _101110703 = '石泉', _101110708 = '白河', _101110709 = '镇坪', _101110701 = '安康', _101110706 = '岚皋', _101110710 = '宁陕', _101110705 = '旬阳', },\n        ['咸阳'] = { _101110202 = '礼泉', _101110205 = '泾阳', _101110203 = '永寿', _101110208 = '彬县', _101110210 = '旬邑', _101110200 = '咸阳', _101110209 = '长武', _101110211 = '兴平', _101110204 = '淳化', _101110207 = '乾县', _101110206 = '武功', _101110201 = '三原', },\n        ['商洛'] = { _101110603 = '柞水', _101110608 = '山阳', _101110604 = '商州', _101110602 = '洛南', _101110607 = '商南', _101110606 = '丹凤', _101110601 = '商洛', _101110605 = '镇安', },\n        ['汉中'] = { _101110801 = '汉中', _101110807 = '西乡', _101110805 = '洋县', _101110810 = '南郑', _101110808 = '佛坪', _101110804 = '留坝', _101110809 = '宁强', _101110811 = '镇巴', _101110803 = '勉县', _101110806 = '城固', _101110802 = '略阳', },\n    },\n    ['四川'] = {\n        ['资阳'] = { _101271303 = '乐至', _101271304 = '简阳', _101271302 = '安岳', _101271301 = '资阳', },\n        ['遂宁'] = { _101270703 = '射洪', _101270701 = '遂宁', _101270702 = '蓬溪', },\n        ['阿坝'] = { _101271904 = '茂县', _101271905 = '松潘', _101271910 = '马尔康', _101271902 = '汶川', _101271908 = '小金', _101271911 = '壤塘', _101271912 = '若尔盖', _101271901 = '阿坝', _101271906 = '九寨沟', _101271907 = '金川', _101271913 = '红原', _101271903 = '理县', _101271909 = '黑水', },\n        ['绵阳'] = { _101270402 = '三台', _101270408 = '江油', _101270404 = '安县', _101270401 = '绵阳', _101270406 = '北川', _101270405 = '梓潼', _101270403 = '盐亭', _101270407 = '平武', },\n        ['成都'] = { _101270115 = '青白江', _101270113 = '邛崃', _101270114 = '崇州', _101270109 = '蒲江', _101270108 = '大邑', _101270102 = '龙泉驿', _101270107 = '郫县', _101270105 = '金堂', _101270103 = '新都', _101270110 = '新津', _101270104 = '温江', _101270111 = '都江堰', _101270106 = '双流', _101270112 = '彭州', _101270101 = '成都', },\n        ['内江'] = { _101271201 = '内江', _101271204 = '资中', _101271203 = '威远', _101271205 = '隆昌', _101271202 = '东兴', },\n        ['广元'] = { _101272102 = '旺苍', _101272103 = '青川', _101272105 = '苍溪', _101272101 = '广元', _101272104 = '剑阁', },\n        ['达州'] = { _101270602 = '宣汉', _101270608 = '达川', _101270601 = '达州', _101270605 = '渠县', _101270607 = '通川', _101270606 = '万源', _101270604 = '大竹', _101270603 = '开江', },\n        ['德阳'] = { _101272005 = '绵竹', _101272001 = '德阳', _101272006 = '罗江', _101272002 = '中江', _101272003 = '广汉', _101272004 = '什邡', },\n        ['泸州'] = { _101271005 = '叙永', _101271006 = '古蔺', _101271007 = '纳溪', _101271004 = '合江', _101271003 = '泸县', _101271001 = '泸州', },\n        ['雅安'] = { _101271704 = '汉源', _101271703 = '荥经', _101271708 = '宝兴', _101271706 = '天全', _101271707 = '芦山', _101271702 = '名山', _101271701 = '雅安', _101271705 = '石棉', },\n        ['南充'] = { _101270504 = '蓬安', _101270506 = '西充', _101270507 = '阆中', _101270505 = '仪陇', _101270501 = '南充', _101270502 = '南部', _101270503 = '营山', },\n        ['宜宾'] = { _101271103 = '宜宾县', _101271110 = '兴文', _101271106 = '长宁', _101271101 = '宜宾', _101271111 = '屏山', _101271105 = '江安', _101271107 = '高县', _101271109 = '筠连', _101271108 = '珙县', _101271104 = '南溪', },\n        ['巴中'] = { _101270901 = '巴中', _101270903 = '南江', _101270902 = '通江', _101270904 = '平昌', },\n        ['自贡'] = { _101270303 = '荣县', _101270301 = '自贡', _101270302 = '富顺', },\n        ['广安'] = { _101270802 = '岳池', _101270801 = '广安', _101270805 = '华蓥', _101270803 = '武胜', _101270804 = '邻水', },\n        ['凉山'] = { _101271614 = '冕宁', _101271610 = '西昌', _101271615 = '越西', _101271611 = '金阳', _101271616 = '甘洛', _101271604 = '盐源', _101271605 = '德昌', _101271617 = '雷波', _101271609 = '普格', _101271612 = '昭觉', _101271603 = '木里', _101271619 = '布拖', _101271618 = '美姑', _101271613 = '喜德', _101271607 = '会东', _101271601 = '凉山', _101271606 = '会理', _101271608 = '宁南', },\n        ['乐山'] = { _101271406 = '峨边', _101271405 = '沐川', _101271402 = '犍为', _101271404 = '夹江', _101271401 = '乐山', _101271407 = '马边', _101271409 = '峨眉山', _101271403 = '井研', _101271408 = '峨眉', },\n        ['眉山'] = { _101271502 = '仁寿', _101271504 = '洪雅', _101271506 = '青神', _101271501 = '眉山', _101271505 = '丹棱', _101271503 = '彭山', },\n        ['甘孜'] = { _101271813 = '色达', _101271815 = '巴塘', _101271811 = '白玉', _101271814 = '理塘', _101271810 = '德格', _101271803 = '泸定', _101271806 = '雅江', _101271805 = '九龙', _101271816 = '乡城', _101271804 = '丹巴', _101271812 = '石渠', _101271808 = '炉霍', _101271817 = '稻城', _101271802 = '康定', _101271818 = '得荣', _101271809 = '新龙', _101271801 = '甘孜', _101271807 = '道孚', },\n        ['攀枝花'] = { _101270202 = '仁和', _101270203 = '米易', _101270204 = '盐边', _101270201 = '攀枝花', },\n    },\n    ['台湾'] = {\n        ['高雄'] = { _101340202 = '嘉义', _101340203 = '台南', _101340205 = '屏东', _101340201 = '高雄', _101340204 = '台东', },\n        ['台中'] = { _101340402 = '苗栗', _101340404 = '南投', _101340405 = '花莲', _101340406 = '云林', _101340403 = '彰化', _101340401 = '台中', },\n        ['台北'] = { _101340101 = '台北', _101340102 = '桃园', _101340103 = '新竹', _101340104 = '宜兰', },\n    },\n    ['澳门'] = {\n        ['澳门'] = { _101330101 = '澳门', _101330102 = '氹仔岛', _101330103 = '路环岛', },\n    },\n    ['香港'] = {\n        ['香港'] = { _101320103 = '新界', _101320101 = '香港', _101320102 = '九龙', },\n    },\n    ['云南'] = {\n        ['西双版纳'] = { _101291603 = '勐海', _101291601 = '景洪', _101291605 = '勐腊', },\n        ['玉溪'] = { _101290704 = '通海', _101290705 = '华宁', _101290702 = '澄江', _101290709 = '元江', _101290708 = '峨山', _101290706 = '新平', _101290707 = '易门', _101290701 = '玉溪', _101290703 = '江川', },\n        ['丽江'] = { _101291404 = '宁蒗', _101291402 = '永胜', _101291401 = '丽江', _101291403 = '华坪', },\n        ['临沧'] = { _101291104 = '双江', _101291108 = '镇康', _101291103 = '耿马', _101291101 = '临沧', _101291106 = '永德', _101291105 = '凤庆', _101291107 = '云县', _101291102 = '沧源', },\n        ['曲靖'] = { _101290409 = '宣威', _101290402 = '沾益', _101290401 = '曲靖', _101290404 = '富源', _101290406 = '师宗', _101290408 = '会泽', _101290403 = '陆良', _101290405 = '马龙', _101290407 = '罗平', },\n        ['德宏'] = { _101291503 = '陇川', _101291501 = '德宏', _101291506 = '瑞丽', _101291507 = '梁河', _101291508 = '芒市', _101291504 = '盈江', },\n        ['迪庆'] = { _101291302 = '德钦', _101291303 = '维西', _101291301 = '香格里拉', _101291304 = '中甸', },\n        ['怒江'] = { _101291201 = '怒江', _101291203 = '福贡', _101291204 = '兰坪', _101291207 = '贡山', _101291206 = '六库', _101291205 = '泸水', },\n        ['文山'] = { _101290601 = '文山', _101290604 = '麻栗坡', _101290603 = '马关', _101290605 = '砚山', _101290608 = '富宁', _101290606 = '丘北', _101290602 = '西畴', _101290607 = '广南', },\n        ['昭通'] = { _101291005 = '威信', _101291009 = '盐津', _101291004 = '镇雄', _101291010 = '大关', _101291002 = '鲁甸', _101291011 = '水富', _101291006 = '巧家', _101291001 = '昭通', _101291003 = '彝良', _101291007 = '绥江', _101291008 = '永善', },\n        ['保山'] = { _101290504 = '施甸', _101290505 = '昌宁', _101290503 = '龙陵', _101290501 = '保山', _101290506 = '腾冲', },\n        ['楚雄'] = { _101290806 = '南华', _101290801 = '楚雄', _101290804 = '姚安', _101290810 = '永仁', _101290809 = '双柏', _101290808 = '禄丰', _101290807 = '武定', _101290805 = '牟定', _101290803 = '元谋', _101290802 = '大姚', },\n        ['昆明'] = { _101290104 = '寻甸', _101290111 = '禄劝', _101290106 = '宜良', _101290112 = '安宁', _101290105 = '晋宁', _101290113 = '太华山', _101290110 = '嵩明', _101290107 = '石林', _101290101 = '昆明', _101290109 = '富民', _101290108 = '呈贡', _101290103 = '东川', },\n        ['普洱'] = { _101290912 = '宁洱', _101290907 = '江城', _101290903 = '景东', _101290906 = '墨江', _101290911 = '镇沅', _101290909 = '西盟', _101290908 = '孟连', _101290901 = '普洱', _101290902 = '景谷', _101290904 = '澜沧', },\n        ['大理'] = { _101290208 = '巍山', _101290209 = '剑川', _101290206 = '弥渡', _101290212 = '南涧', _101290210 = '洱源', _101290211 = '鹤庆', _101290204 = '永平', _101290205 = '宾川', _101290207 = '祥云', _101290201 = '大理', _101290202 = '云龙', _101290203 = '漾濞', },\n        ['红河'] = { _101290306 = '绿春', _101290305 = '元阳', _101290301 = '红河', _101290313 = '河口', _101290307 = '开远', _101290310 = '屏边', _101290302 = '石屏', _101290311 = '泸西', _101290309 = '蒙自', _101290308 = '个旧', _101290312 = '金平', _101290303 = '建水', _101290304 = '弥勒', },\n    },\n    ['广西'] = {\n        ['南宁'] = { _101300104 = '横县', _101300101 = '南宁', _101300103 = '邕宁', _101300105 = '隆安', _101300108 = '武鸣', _101300109 = '宾阳', _101300107 = '上林', _101300106 = '马山', },\n        ['玉林'] = { _101300905 = '陆川', _101300901 = '玉林', _101300906 = '兴业', _101300904 = '容县', _101300903 = '北流', _101300902 = '博白', },\n        ['崇左'] = { _101300203 = '龙州', _101300202 = '天等', _101300201 = '崇左', _101300206 = '扶绥', _101300205 = '大新', _101300204 = '凭祥', _101300207 = '宁明', },\n        ['柳州'] = { _101300308 = '三江', _101300307 = '融水', _101300302 = '柳城', _101300301 = '柳州', _101300305 = '柳江', _101300306 = '融安', _101300304 = '鹿寨', },\n        ['桂林'] = { _101300506 = '兴安', _101300512 = '平乐', _101300513 = '荔浦', _101300501 = '桂林', _101300514 = '资源', _101300507 = '灵川', _101300511 = '恭城', _101300508 = '全州', _101300510 = '阳朔', _101300504 = '永福', _101300509 = '灌阳', _101300503 = '龙胜', _101300505 = '临桂', },\n        ['来宾'] = { _101300403 = '金秀', _101300404 = '象州', _101300405 = '武宣', _101300402 = '忻城', _101300406 = '合山', _101300401 = '来宾', },\n        ['防城港'] = { _101301403 = '东兴', _101301405 = '防城', _101301401 = '防城港', _101301402 = '上思', },\n        ['北海'] = { _101301301 = '北海', _101301302 = '合浦', _101301303 = '涠洲岛', },\n        ['河池'] = { _101301202 = '天峨', _101301205 = '环江', _101301207 = '宜州', _101301204 = '巴马', _101301210 = '都安', _101301201 = '河池', _101301208 = '凤山', _101301211 = '大化', _101301203 = '东兰', _101301206 = '罗城', _101301209 = '南丹', },\n        ['钦州'] = { _101301103 = '灵山', _101301102 = '浦北', _101301101 = '钦州', },\n        ['梧州'] = { _101300604 = '苍梧', _101300602 = '藤县', _101300601 = '梧州', _101300605 = '蒙山', _101300606 = '岑溪', },\n        ['百色'] = { _101301011 = '凌云', _101301010 = '乐业', _101301007 = '平果', _101301009 = '西林', _101301008 = '隆林', _101301005 = '靖西', _101301012 = '田林', _101301006 = '田东', _101301002 = '那坡', _101301001 = '百色', _101301004 = '德保', _101301003 = '田阳', },\n        ['贵港'] = { _101300802 = '桂平', _101300801 = '贵港', _101300803 = '平南', },\n        ['贺州'] = { _101300704 = '钟山', _101300703 = '富川', _101300702 = '昭平', _101300701 = '贺州', },\n    },\n    ['内蒙古'] = {\n        ['通辽'] = { _101080501 = '通辽', _101080509 = '扎鲁特', _101080507 = '库伦', _101080508 = '奈曼', _101080511 = '巴雅尔吐胡硕', _101080512 = '霍林郭勒', _101080506 = '开鲁', _101080505 = '青龙山', _101080504 = '科左后旗', _101080502 = '舍伯吐', _101080503 = '科左中旗', },\n        ['呼伦贝尔'] = { _101081006 = '鄂温克旗', _101081005 = '鄂伦春旗', _101081008 = '新左旗', _101081015 = '根河', _101081003 = '阿荣旗', _101081009 = '新右旗', _101081002 = '小二沟', _101081007 = '陈旗', _101081012 = '扎兰屯', _101081014 = '额尔古纳', _101081004 = '莫力达瓦', _101081011 = '牙克石', _101081010 = '满洲里', _101081016 = '图里河', _101081001 = '海拉尔', },\n        ['乌海'] = { _101080301 = '乌海', },\n        ['乌兰察布'] = { _101080412 = '丰镇', _101080406 = '兴和', _101080401 = '集宁', _101080404 = '商都', _101080409 = '察右中旗', _101080408 = '察右前旗', _101080407 = '凉城', _101080403 = '化德', _101080410 = '察右后旗', _101080411 = '四子王旗', _101080402 = '卓资', },\n        ['巴彦淖尔'] = { _101080803 = '磴口', _101080806 = '乌中旗', _101080801 = '临河', _101080809 = '那仁宝力格', _101080808 = '海力素', _101080805 = '大佘太', _101080802 = '五原', _101080807 = '乌后旗', _101080810 = '杭锦后旗', _101080804 = '乌前旗', },\n        ['阿拉善盟'] = { _101081208 = '中泉子', _101081211 = '乌斯太', _101081206 = '锡林高勒', _101081205 = '吉兰太', _101081209 = '巴彦诺日公', _101081202 = '阿右旗', _101081201 = '阿左旗', _101081210 = '雅布赖', _101081203 = '额济纳', _101081207 = '头道湖', _101081212 = '孪井滩', _101081204 = '拐子湖', },\n        ['兴安盟'] = { _101081104 = '胡尔勒', _101081102 = '阿尔山', _101081105 = '扎赉特', _101081107 = '突泉', _101081109 = '科右前旗', _101081110 = '高力板', _101081103 = '科右中旗', _101081101 = '乌兰浩特', _101081106 = '索伦', },\n        ['锡林郭勒'] = { _101080909 = '东乌旗', _101080901 = '锡林浩特', _101080907 = '苏右旗', _101080910 = '西乌旗', _101080911 = '太仆寺', _101080906 = '苏左旗', _101080913 = '正镶白旗', _101080903 = '二连浩特', _101080916 = '博克图', _101080915 = '多伦', _101080904 = '阿巴嘎', _101080908 = '朱日和', _101080914 = '正蓝旗', _101080912 = '镶黄旗', _101080917 = '乌拉盖', },\n        ['鄂尔多斯'] = { _101080708 = '鄂托克', _101080703 = '达拉特', _101080707 = '伊和乌素', _101080706 = '河南', _101080701 = '鄂尔多斯', _101080712 = '乌审召', _101080705 = '鄂前旗', _101080713 = '东胜', _101080711 = '伊金霍洛', _101080710 = '乌审旗', _101080709 = '杭锦旗', _101080704 = '准格尔', },\n        ['赤峰'] = { _101080606 = '巴林右旗', _101080611 = '喀喇沁', _101080605 = '巴林左旗', _101080601 = '赤峰', _101080608 = '克什克腾', _101080609 = '翁牛特', _101080613 = '宁城', _101080610 = '岗子', _101080612 = '八里罕', _101080604 = '浩尔吐', _101080614 = '敖汉', _101080615 = '宝国吐', _101080607 = '林西', _101080603 = '阿鲁旗', },\n        ['包头'] = { _101080202 = '白云鄂博', _101080207 = '希拉穆仁', _101080206 = '达茂旗', _101080205 = '固阳', _101080203 = '满都拉', _101080204 = '土右旗', _101080201 = '包头', },\n        ['呼和浩特'] = { _101080103 = '托县', _101080102 = '土左旗', _101080107 = '武川', _101080105 = '清水河', _101080106 = '赛罕', _101080104 = '和林', _101080101 = '呼和浩特', },\n    },\n    ['重庆'] = {\n        ['重庆'] = { _101042000 = '巫山', _101042400 = '忠县', _101040800 = '北碚', _101040300 = '合川', _101042900 = '璧山', _101042200 = '垫江', _101042800 = '铜梁', _101043200 = '彭水', _101040900 = '巴南', _101041000 = '长寿', _101041900 = '奉节', _101043300 = '綦江', _101041400 = '涪陵', _101040500 = '江津', _101042100 = '潼南', _101043400 = '酉阳', _101042600 = '大足', _101041700 = '云阳', _101041100 = '黔江', _101041600 = '城口', _101043100 = '武隆', _101043000 = '丰都', _101040400 = '南川', _101042500 = '石柱', _101041300 = '万州', _101042300 = '梁平', _101041800 = '巫溪', _101040100 = '重庆', _101040700 = '渝北', _101041500 = '开县', _101043600 = '秀山', _101042700 = '荣昌', _101040600 = '万盛', _101040200 = '永川', },\n    },\n    ['山西'] = {\n        ['运城'] = { _101100801 = '运城', _101100802 = '临猗', _101100808 = '闻喜', _101100813 = '平陆', _101100809 = '垣曲', _101100811 = '芮城', _101100806 = '新绛', _101100812 = '夏县', _101100810 = '永济', _101100804 = '万荣', _101100805 = '河津', _101100807 = '绛县', _101100803 = '稷山', },\n        ['大同'] = { _101100202 = '阳高', _101100201 = '大同', _101100208 = '左云', _101100207 = '浑源', _101100206 = '灵丘', _101100203 = '大同县', _101100204 = '天镇', _101100205 = '广灵', },\n        ['临汾'] = { _101100707 = '襄汾', _101100713 = '翼城', _101100717 = '古县', _101100711 = '霍州', _101100716 = '安泽', _101100702 = '曲沃', _101100715 = '浮山', _101100708 = '蒲县', _101100701 = '临汾', _101100709 = '汾西', _101100705 = '大宁', _101100706 = '吉县', _101100710 = '洪洞', _101100704 = '隰县', _101100712 = '乡宁', _101100714 = '侯马', _101100703 = '永和', },\n        ['朔州'] = { _101100903 = '山阴', _101100902 = '平鲁', _101100904 = '右玉', _101100906 = '怀仁', _101100905 = '应县', _101100901 = '朔州', },\n        ['太原'] = { _101100101 = '太原', _101100105 = '古交', _101100104 = '娄烦', _101100107 = '小店区', _101100103 = '阳曲', _101100102 = '清徐', _101100106 = '尖草坪区', },\n        ['长治'] = { _101100505 = '襄垣', _101100510 = '沁源', _101100503 = '屯留', _101100507 = '武乡', _101100501 = '长治', _101100506 = '平顺', _101100508 = '沁县', _101100504 = '潞城', _101100509 = '长子', _101100502 = '黎城', _101100511 = '壶关', },\n        ['吕梁'] = { _101101104 = '岚县', _101101112 = '文水', _101101110 = '孝义', _101101103 = '兴县', _101101105 = '柳林', _101101101 = '离石', _101101113 = '交城', _101101109 = '中阳', _101101111 = '汾阳', _101101107 = '方山', _101101102 = '临县', _101101106 = '石楼', _101101108 = '交口', _101101100 = '吕梁', },\n        ['忻州'] = { _101101004 = '河曲', _101101005 = '偏关', _101101012 = '静乐', _101101014 = '五寨', _101101011 = '保德', _101101008 = '代县', _101101001 = '忻州', _101101007 = '宁武', _101101015 = '原平', _101101006 = '神池', _101101010 = '五台山', _101101002 = '定襄', _101101009 = '繁峙', _101101003 = '五台县', _101101013 = '岢岚', },\n        ['晋中'] = { _101100410 = '平遥', _101100404 = '左权', _101100408 = '太谷', _101100409 = '祁县', _101100402 = '榆次', _101100403 = '榆社', _101100407 = '寿阳', _101100405 = '和顺', _101100412 = '介休', _101100401 = '晋中', _101100411 = '灵石', _101100406 = '昔阳', },\n        ['阳泉'] = { _101100301 = '阳泉', _101100302 = '盂县', _101100303 = '平定', },\n        ['晋城'] = { _101100604 = '陵川', _101100606 = '泽州', _101100605 = '高平', _101100603 = '阳城', _101100601 = '晋城', _101100602 = '沁水', },\n    },\n    ['河南'] = {\n        ['安阳'] = { _101180204 = '内黄', _101180203 = '滑县', _101180205 = '林州', _101180202 = '汤阴', _101180201 = '安阳', },\n        ['濮阳'] = { _101181303 = '南乐', _101181301 = '濮阳', _101181304 = '清丰', _101181302 = '台前', _101181305 = '范县', },\n        ['焦作'] = { _101181108 = '孟州', _101181104 = '沁阳', _101181101 = '焦作', _101181102 = '修武', _101181107 = '温县', _101181106 = '博爱', _101181103 = '武陟', },\n        ['开封'] = { _101180803 = '尉氏', _101180804 = '通许', _101180805 = '兰考', _101180802 = '杞县', _101180801 = '开封', },\n        ['周口'] = { _101181408 = '郸城', _101181406 = '商水', _101181404 = '淮阳', _101181401 = '周口', _101181403 = '太康', _101181410 = '沈丘', _101181409 = '鹿邑', _101181407 = '项城', _101181402 = '扶沟', _101181405 = '西华', },\n        ['三门峡'] = { _101181702 = '灵宝', _101181704 = '卢氏', _101181706 = '陕县', _101181703 = '渑池', _101181705 = '义马', _101181701 = '三门峡', },\n        ['许昌'] = { _101180401 = '许昌', _101180403 = '襄城', _101180405 = '禹州', _101180404 = '长葛', _101180402 = '鄢陵', },\n        ['洛阳'] = { _101180906 = '伊川', _101180905 = '洛宁', _101180911 = '吉利', _101180903 = '孟津', _101180901 = '洛阳', _101180907 = '嵩县', _101180910 = '汝阳', _101180908 = '偃师', _101180909 = '栾川', _101180902 = '新安', _101180904 = '宜阳', },\n        ['南阳'] = { _101180702 = '南召', _101180704 = '社旗', _101180707 = '镇平', _101180703 = '方城', _101180709 = '新野', _101180705 = '西峡', _101180708 = '淅川', _101180701 = '南阳', _101180711 = '邓州', _101180710 = '唐河', _101180712 = '桐柏', _101180706 = '内乡', },\n        ['济源'] = { _101181801 = '济源', },\n        ['漯河'] = { _101181501 = '漯河', _101181502 = '临颍', _101181503 = '舞阳', },\n        ['信阳'] = { _101180607 = '潢川', _101180609 = '商城', _101180604 = '光山', _101180602 = '息县', _101180608 = '固始', _101180605 = '新县', _101180603 = '罗山', _101180601 = '信阳', _101180606 = '淮滨', },\n        ['商丘'] = { _101181009 = '永城', _101181005 = '虞城', _101181006 = '柘城', _101181003 = '睢县', _101181007 = '宁陵', _101181008 = '夏邑', _101181004 = '民权', _101181001 = '商丘', },\n        ['驻马店'] = { _101181609 = '确山', _101181601 = '驻马店', _101181608 = '新蔡', _101181603 = '遂平', _101181610 = '正阳', _101181602 = '西平', _101181605 = '汝南', _101181604 = '上蔡', _101181606 = '泌阳', _101181607 = '平舆', },\n        ['郑州'] = { _101180104 = '登封', _101180101 = '郑州', _101180106 = '新郑', _101180102 = '巩义', _101180105 = '新密', _101180108 = '上街', _101180107 = '中牟', _101180103 = '荥阳', },\n        ['平顶山'] = { _101180505 = '叶县', _101180503 = '宝丰', _101180507 = '鲁山', _101180501 = '平顶山', _101180502 = '郏县', _101180504 = '汝州', _101180506 = '舞钢', _101180508 = '石龙', },\n        ['鹤壁'] = { _101181203 = '淇县', _101181202 = '浚县', _101181201 = '鹤壁', },\n        ['新乡'] = { _101180302 = '获嘉', _101180305 = '卫辉', _101180307 = '封丘', _101180306 = '延津', _101180303 = '原阳', _101180308 = '长垣', _101180304 = '辉县', _101180301 = '新乡', },\n    },\n    ['河北'] = {\n        ['沧州'] = { _101090706 = '肃宁', _101090711 = '泊头', _101090709 = '献县', _101090716 = '沧县', _101090705 = '盐山', _101090710 = '孟村', _101090703 = '东光', _101090702 = '青县', _101090707 = '南皮', _101090713 = '黄骅', _101090714 = '河间', _101090708 = '吴桥', _101090704 = '海兴', _101090701 = '沧州', _101090712 = '任丘', },\n        ['邢台'] = { _101090916 = '南宫', _101090911 = '广宗', _101090909 = '巨鹿', _101090912 = '平乡', _101090906 = '隆尧', _101090905 = '柏乡', _101090917 = '沙河', _101090901 = '邢台', _101090914 = '清河', _101090908 = '宁晋', _101090913 = '威县', _101090910 = '新河', _101090918 = '任县', _101090907 = '南和', _101090915 = '临西', _101090902 = '临城', _101090904 = '内丘', },\n        ['廊坊'] = { _101090601 = '廊坊', _101090604 = '香河', _101090607 = '大厂', _101090602 = '固安', _101090609 = '三河', _101090608 = '霸州', _101090605 = '大城', _101090606 = '文安', _101090603 = '永清', },\n        ['保定'] = { _101090215 = '蠡县', _101090201 = '保定', _101090211 = '安新', _101090209 = '涞源', _101090204 = '徐水', _101090207 = '容城', _101090220 = '安国', _101090217 = '雄县', _101090214 = '曲阳', _101090210 = '望都', _101090203 = '阜平', _101090225 = '博野', _101090218 = '涿州', _101090224 = '清苑', _101090216 = '顺平', _101090219 = '定州', _101090223 = '定兴', _101090222 = '涞水', _101090221 = '高碑店', _101090206 = '高阳', _101090212 = '易县', _101090205 = '唐县', _101090202 = '满城', },\n        ['唐山'] = { _101090502 = '丰南', _101090504 = '滦县', _101090505 = '滦南', _101090507 = '迁西', _101090501 = '唐山', _101090512 = '曹妃甸工业区', _101090510 = '遵化', _101090506 = '乐亭', _101090503 = '丰润', _101090508 = '玉田', _101090509 = '曹妃甸', _101090511 = '迁安', },\n        ['邯郸'] = { _101091006 = '涉县', _101091008 = '肥乡', _101091004 = '成安', _101091016 = '武安', _101091015 = '曲周', _101091001 = '邯郸', _101091002 = '峰峰', _101091010 = '邱县', _101091013 = '馆陶', _101091012 = '广平', _101091007 = '磁县', _101091005 = '大名', _101091009 = '永年', _101091011 = '鸡泽', _101091003 = '临漳', _101091014 = '魏县', },\n        ['秦皇岛'] = { _101091101 = '秦皇岛', _101091106 = '北戴河', _101091103 = '昌黎', _101091105 = '卢龙', _101091102 = '青龙', _101091104 = '抚宁', },\n        ['张家口'] = { _101090301 = '张家口', _101090306 = '尚义', _101090313 = '赤城', _101090310 = '万全', _101090308 = '阳原', _101090312 = '涿鹿', _101090304 = '康保', _101090309 = '怀安', _101090314 = '崇礼', _101090302 = '宣化', _101090311 = '怀来', _101090303 = '张北', _101090305 = '沽源', _101090307 = '蔚县', },\n        ['石家庄'] = { _101090107 = '高邑', _101090103 = '正定', _101090110 = '无极', _101090112 = '元氏', _101090111 = '平山', _101090108 = '深泽', _101090102 = '井陉', _101090106 = '灵寿', _101090109 = '赞皇', _101090113 = '赵县', _101090115 = '藁城', _101090114 = '辛集', _101090118 = '鹿泉', _101090117 = '新乐', _101090116 = '晋州', _101090101 = '石家庄', _101090104 = '栾城', _101090105 = '行唐', },\n        ['承德'] = { _101090407 = '隆化', _101090404 = '兴隆', _101090406 = '滦平', _101090403 = '承德县', _101090405 = '平泉', _101090409 = '宽城', _101090410 = '围场', _101090402 = '承德', _101090408 = '丰宁', },\n        ['衡水'] = { _101090805 = '饶阳', _101090809 = '阜城', _101090803 = '武邑', _101090804 = '武强', _101090806 = '安平', _101090811 = '深州', _101090808 = '景县', _101090802 = '枣强', _101090810 = '冀州', _101090801 = '衡水', _101090807 = '故城', },\n    },\n    ['贵州'] = {\n        ['铜仁'] = { _101260605 = '思南', _101260602 = '江口', _101260603 = '玉屏', _101260604 = '万山', _101260609 = '沿河', _101260601 = '铜仁', _101260610 = '德江', _101260608 = '石阡', _101260611 = '松桃', _101260607 = '印江', },\n        ['遵义'] = { _101260214 = '汇川', _101260203 = '仁怀', _101260205 = '湄潭', _101260215 = '红花岗', _101260207 = '桐梓', _101260212 = '务川', _101260211 = '正安', _101260208 = '赤水', _101260209 = '习水', _101260210 = '道真', _101260213 = '余庆', _101260201 = '遵义', _101260202 = '遵义县', _101260204 = '绥阳', _101260206 = '凤冈', },\n        ['黔东南'] = { _101260515 = '锦屏', _101260505 = '黄平', _101260501 = '凯里', _101260514 = '天柱', _101260516 = '榕江', _101260503 = '施秉', _101260511 = '剑河', _101260508 = '丹寨', _101260504 = '镇远', _101260513 = '黎平', _101260512 = '雷山', _101260507 = '麻江', _101260502 = '岑巩', _101260517 = '从江', _101260509 = '三穗', _101260510 = '台江', },\n        ['贵阳'] = { _101260110 = '云岩', _101260103 = '花溪', _101260102 = '白云', _101260101 = '贵阳', _101260106 = '开阳', _101260111 = '南明', _101260104 = '乌当', _101260109 = '小河', _101260108 = '清镇', _101260107 = '修文', _101260105 = '息烽', },\n        ['六盘水'] = { _101260804 = '盘县', _101260802 = '六枝', _101260801 = '水城', },\n        ['黔西南'] = { _101260908 = '册亨', _101260901 = '兴义', _101260904 = '贞丰', _101260902 = '晴隆', _101260909 = '普安', _101260903 = '兴仁', _101260907 = '安龙', _101260905 = '望谟', },\n        ['毕节'] = { _101260703 = '金沙', _101260707 = '织金', _101260708 = '黔西', _101260706 = '纳雍', _101260701 = '毕节', _101260704 = '威宁', _101260702 = '赫章', _101260705 = '大方', },\n        ['黔南'] = { _101260404 = '长顺', _101260405 = '福泉', _101260402 = '贵定', _101260411 = '三都', _101260407 = '龙里', _101260410 = '独山', _101260403 = '瓮安', _101260406 = '惠水', _101260412 = '荔波', _101260409 = '平塘', _101260401 = '都匀', _101260408 = '罗甸', },\n        ['安顺'] = { _101260303 = '镇宁', _101260302 = '普定', _101260306 = '关岭', _101260301 = '安顺', _101260305 = '紫云', _101260304 = '平坝', },\n    },\n    ['福建'] = {\n        ['钓鱼岛'] = { _101231001 = '钓鱼岛', },\n        ['南平'] = { _101230901 = '南平', _101230905 = '武夷山', _101230907 = '建阳', _101230910 = '建瓯', _101230904 = '邵武', _101230903 = '光泽', _101230909 = '政和', _101230908 = '松溪', _101230902 = '顺昌', _101230906 = '浦城', },\n        ['福州'] = { _101230111 = '福清', _101230110 = '长乐', _101230104 = '罗源', _101230101 = '福州', _101230102 = '闽清', _101230103 = '闽侯', _101230108 = '平潭', _101230105 = '连江', _101230107 = '永泰', },\n        ['三明'] = { _101230802 = '宁化', _101230807 = '明溪', _101230805 = '将乐', _101230804 = '泰宁', _101230801 = '三明', _101230808 = '沙县', _101230803 = '清流', _101230809 = '尤溪', _101230810 = '永安', _101230811 = '大田', _101230806 = '建宁', },\n        ['龙岩'] = { _101230701 = '龙岩', _101230706 = '永定', _101230705 = '上杭', _101230707 = '漳平', _101230704 = '武平', _101230702 = '长汀', _101230703 = '连城', },\n        ['泉州'] = { _101230504 = '永春', _101230509 = '晋江', _101230508 = '惠安', _101230510 = '石狮', _101230506 = '南安', _101230507 = '崇武', _101230502 = '安溪', _101230505 = '德化', _101230501 = '泉州', },\n        ['厦门'] = { _101230202 = '同安', _101230201 = '厦门', },\n        ['莆田'] = { _101230406 = '荔城', _101230402 = '仙游', _101230403 = '秀屿港', _101230407 = '城厢', _101230401 = '莆田', _101230405 = '秀屿', _101230404 = '涵江', },\n        ['漳州'] = { _101230608 = '东山', _101230604 = '平和', _101230605 = '龙海', _101230607 = '诏安', _101230610 = '华安', _101230609 = '云霄', _101230601 = '漳州', _101230602 = '长泰', _101230603 = '南靖', _101230606 = '漳浦', },\n        ['宁德'] = { _101230306 = '福安', _101230303 = '霞浦', _101230304 = '寿宁', _101230302 = '古田', _101230308 = '福鼎', _101230309 = '屏南', _101230301 = '宁德', _101230305 = '周宁', _101230307 = '柘荣', },\n    },\n    ['江苏'] = {\n        ['镇江'] = { _101190301 = '镇江', _101190303 = '扬中', _101190304 = '句容', _101190305 = '丹徒', _101190302 = '丹阳', },\n        ['扬州'] = { _101190606 = '邗江', _101190603 = '仪征', _101190601 = '扬州', _101190605 = '江都', _101190602 = '宝应', _101190604 = '高邮', },\n        ['宿迁'] = { _101191303 = '泗阳', _101191302 = '沭阳', _101191305 = '宿豫', _101191301 = '宿迁', _101191304 = '泗洪', },\n        ['苏州'] = { _101190405 = '吴中', _101190407 = '吴江', _101190402 = '常熟', _101190408 = '太仓', _101190403 = '张家港', _101190401 = '苏州', _101190404 = '昆山', },\n        ['南京'] = { _101190105 = '六合', _101190106 = '江浦', _101190103 = '高淳', _101190102 = '溧水', _101190107 = '浦口', _101190104 = '江宁', _101190101 = '南京', },\n        ['无锡'] = { _101190202 = '江阴', _101190203 = '宜兴', _101190201 = '无锡', _101190204 = '锡山', },\n        ['泰州'] = { _101191201 = '泰州', _101191204 = '姜堰', _101191203 = '泰兴', _101191202 = '兴化', _101191205 = '靖江', },\n        ['盐城'] = { _101190707 = '东台', _101190702 = '响水', _101190706 = '建湖', _101190705 = '射阳', _101190703 = '滨海', _101190701 = '盐城', _101190708 = '大丰', _101190709 = '盐都', _101190704 = '阜宁', },\n        ['常州'] = { _101191102 = '溧阳', _101191104 = '武进', _101191103 = '金坛', _101191101 = '常州', },\n        ['徐州'] = { _101190803 = '丰县', _101190807 = '新沂', _101190802 = '铜山', _101190801 = '徐州', _101190806 = '睢宁', _101190804 = '沛县', _101190805 = '邳州', },\n        ['连云港'] = { _101191004 = '灌云', _101191003 = '赣榆', _101191002 = '东海', _101191001 = '连云港', _101191005 = '灌南', },\n        ['淮安'] = { _101190908 = '淮安区', _101190903 = '盱眙', _101190904 = '洪泽', _101190901 = '淮安', _101190906 = '淮阴区', _101190905 = '涟水', _101190902 = '金湖', },\n        ['南通'] = { _101190501 = '南通', _101190509 = '通州', _101190502 = '海安', _101190504 = '如东', _101190503 = '如皋', _101190508 = '海门', _101190507 = '启东', },\n    },\n    ['山东'] = {\n        ['滨州'] = { _101121106 = '沾化', _101121101 = '滨州', _101121105 = '惠民', _101121103 = '无棣', _101121104 = '阳信', _101121107 = '邹平', _101121102 = '博兴', },\n        ['泰安'] = { _101120804 = '肥城', _101120801 = '泰安', _101120806 = '宁阳', _101120802 = '新泰', _101120805 = '东平', },\n        ['威海'] = { _101121306 = '石岛', _101121304 = '乳山', _101121302 = '文登', _101121301 = '威海', _101121303 = '荣成', _101121305 = '成山头', },\n        ['济南'] = { _101120106 = '济阳', _101120102 = '长清', _101120104 = '章丘', _101120103 = '商河', _101120105 = '平阴', _101120101 = '济南', },\n        ['东营'] = { _101121204 = '利津', _101121203 = '垦利', _101121202 = '河口', _101121205 = '广饶', _101121201 = '东营', },\n        ['淄博'] = { _101120307 = '桓台', _101120308 = '临淄', _101120306 = '沂源', _101120301 = '淄博', _101120304 = '高青', _101120303 = '博山', _101120305 = '周村', _101120302 = '淄川', },\n        ['潍坊'] = { _101120603 = '寿光', _101120607 = '安丘', _101120604 = '临朐', _101120609 = '诸城', _101120602 = '青州', _101120608 = '高密', _101120606 = '昌邑', _101120605 = '昌乐', _101120601 = '潍坊', },\n        ['青岛'] = { _101120201 = '青岛', _101120208 = '平度', _101120207 = '莱西', _101120204 = '即墨', _101120206 = '黄岛', _101120205 = '胶州', _101120202 = '崂山', },\n        ['莱芜'] = { _101121601 = '莱芜', },\n        ['日照'] = { _101121503 = '莒县', _101121501 = '日照', _101121502 = '五莲', },\n        ['菏泽'] = { _101121009 = '单县', _101121005 = '定陶', _101121007 = '曹县', _101121006 = '巨野', _101121002 = '鄄城', _101121003 = '郓城', _101121004 = '东明', _101121001 = '菏泽', _101121008 = '成武', },\n        ['烟台'] = { _101120502 = '莱州', _101120509 = '牟平', _101120503 = '长岛', _101120508 = '福山', _101120507 = '栖霞', _101120505 = '龙口', _101120511 = '海阳', _101120510 = '莱阳', _101120506 = '招远', _101120504 = '蓬莱', _101120501 = '烟台', },\n        ['聊城'] = { _101121701 = '聊城', _101121705 = '茌平', _101121703 = '阳谷', _101121707 = '临清', _101121702 = '冠县', _101121706 = '东阿', _101121709 = '莘县', _101121704 = '高唐', },\n        ['济宁'] = { _101120701 = '济宁', _101120708 = '泗水', _101120706 = '金乡', _101120711 = '邹城', _101120710 = '曲阜', _101120709 = '梁山', _101120704 = '鱼台', _101120703 = '微山', _101120705 = '兖州', _101120702 = '嘉祥', _101120707 = '汶上', },\n        ['德州'] = { _101120409 = '宁津', _101120406 = '乐陵', _101120408 = '平原', _101120407 = '庆云', _101120405 = '齐河', _101120403 = '临邑', _101120404 = '陵县', _101120410 = '夏津', _101120401 = '德州', _101120411 = '禹城', _101120402 = '武城', },\n        ['枣庄'] = { _101121402 = '薛城', _101121403 = '峄城', _101121405 = '滕州', _101121401 = '枣庄', _101121404 = '台儿庄', },\n        ['临沂'] = { _101120902 = '莒南', _101120908 = '平邑', _101120909 = '费县', _101120905 = '临沭', _101120910 = '沂水', _101120907 = '蒙阴', _101120901 = '临沂', _101120904 = '兰陵', _101120903 = '沂南', _101120906 = '郯城', },\n    },\n    ['辽宁'] = {\n        ['营口'] = { _101070801 = '营口', _101070802 = '大石桥', _101070803 = '盖州', },\n        ['锦州'] = { _101070706 = '北镇', _101070701 = '锦州', _101070705 = '黑山', _101070704 = '义县', _101070702 = '凌海', },\n        ['葫芦岛'] = { _101071401 = '葫芦岛', _101071403 = '绥中', _101071404 = '兴城', _101071402 = '建昌', },\n        ['抚顺'] = { _101070402 = '新宾', _101070401 = '抚顺', _101070403 = '清原', _101070404 = '章党', },\n        ['辽阳'] = { _101071004 = '弓长岭', _101071002 = '辽阳县', _101071003 = '灯塔', _101071001 = '辽阳', },\n        ['鞍山'] = { _101070303 = '岫岩', _101070304 = '海城', _101070302 = '台安', _101070301 = '鞍山', },\n        ['朝阳'] = { _101071201 = '朝阳', _101071203 = '凌源', _101071205 = '北票', _101071204 = '喀左', _101071207 = '建平县', },\n        ['丹东'] = { _101070602 = '凤城', _101070601 = '丹东', _101070603 = '宽甸', _101070604 = '东港', },\n        ['铁岭'] = { _101071102 = '开原', _101071105 = '调兵山', _101071101 = '铁岭', _101071104 = '西丰', _101071103 = '昌图', },\n        ['盘锦'] = { _101071303 = '盘山', _101071302 = '大洼', _101071301 = '盘锦', },\n        ['大连'] = { _101070203 = '金州', _101070204 = '普兰店', _101070206 = '长海', _101070201 = '大连', _101070205 = '旅顺', _101070207 = '庄河', _101070202 = '瓦房店', },\n        ['沈阳'] = { _101070103 = '辽中', _101070106 = '新民', _101070101 = '沈阳', _101070105 = '法库', _101070104 = '康平', },\n        ['本溪'] = { _101070504 = '桓仁', _101070502 = '本溪县', _101070501 = '本溪', },\n        ['阜新'] = { _101070901 = '阜新', _101070902 = '彰武', },\n    },\n    ['黑龙江'] = {\n        ['佳木斯'] = { _101050405 = '桦南', _101050401 = '佳木斯', _101050407 = '富锦', _101050406 = '同江', _101050402 = '汤原', _101050404 = '桦川', _101050403 = '抚远', },\n        ['伊春'] = { _101050805 = '嘉荫', _101050801 = '伊春', _101050804 = '铁力', _101050802 = '乌伊岭', _101050803 = '五营', },\n        ['齐齐哈尔'] = { _101050209 = '克东', _101050206 = '依安', _101050201 = '齐齐哈尔', _101050203 = '龙江', _101050202 = '讷河', _101050208 = '克山', _101050204 = '甘南', _101050205 = '富裕', _101050207 = '拜泉', _101050210 = '泰来', },\n        ['双鸭山'] = { _101051302 = '集贤', _101051303 = '宝清', _101051301 = '双鸭山', _101051304 = '饶河', _101051305 = '友谊', },\n        ['鹤岗'] = { _101051202 = '绥滨', _101051203 = '萝北', _101051201 = '鹤岗', },\n        ['哈尔滨'] = { _101050107 = '巴彦', _101050106 = '依兰', _101050108 = '通河', _101050105 = '宾县', _101050110 = '延寿', _101050101 = '哈尔滨', _101050113 = '木兰', _101050111 = '尚志', _101050112 = '五常', _101050109 = '方正', _101050102 = '双城', _101050104 = '阿城', _101050103 = '呼兰', },\n        ['鸡西'] = { _101051104 = '鸡东', _101051102 = '虎林', _101051103 = '密山', _101051101 = '鸡西', },\n        ['大庆'] = { _101050903 = '肇州', _101050901 = '大庆', _101050905 = '杜尔伯特', _101050904 = '肇源', _101050902 = '林甸', },\n        ['大兴安岭'] = { _101050706 = '新林', _101050702 = '塔河', _101050701 = '大兴安岭', _101050704 = '呼玛', _101050708 = '加格达奇', _101050705 = '呼中', _101050703 = '漠河', },\n        ['七台河'] = { _101051002 = '七台河', _101051003 = '勃利', },\n        ['黑河'] = { _101050604 = '逊克', _101050605 = '五大连池', _101050603 = '孙吴', _101050606 = '北安', _101050602 = '嫩江', _101050601 = '黑河', },\n        ['牡丹江'] = { _101050302 = '海林', _101050307 = '东宁', _101050304 = '林口', _101050305 = '绥芬河', _101050306 = '宁安', _101050301 = '牡丹江', _101050303 = '穆棱', },\n        ['绥化'] = { _101050502 = '肇东', _101050510 = '绥棱', _101050504 = '海伦', _101050503 = '安达', _101050509 = '庆安', _101050507 = '兰西', _101050506 = '望奎', _101050508 = '青冈', _101050505 = '明水', _101050501 = '绥化', },\n    },\n}\nreturn China"
  },
  {
    "path": "lua/weather/info.json",
    "content": "{\n  \"id\": \"pub.hanks.weather\",\n  \"name\": \"天气\",\n  \"icon\": \"http://ww1.sinaimg.cn/large/8c9b876fly1fh10p6tgqtj2046046jr5.jpg\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.2\",\n  \"versionCode\": 4,\n  \"private\": false,\n  \"desc\": \"简洁的看天气的插件\"\n}\n"
  },
  {
    "path": "lua/weather/list_city.lua",
    "content": "require(\"import\")\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaAdapter\"\n\n\nlocal China = require(\"weather.city\")\nlocal filehelper = require(\"filehelper\")\n\nlocal layout = {\n    LinearLayout,\n    layout_width = \"match\",\n    layout_height = \"match\",\n    orientation = 'vertical',\n    statusBarColor = \"#8CCACE\",\n    {\n        LinearLayout,\n        layout_height = \"56dp\",\n        layout_width = \"match\",\n        orientation = 'vertical',\n        gravity = \"center\",\n        background = \"#8CCACE\",\n        {\n            TextView,\n            paddingLeft = \"16dp\",\n            textSize = \"18sp\",\n            text = \"选择城市\",\n            textColor = \"#eeffffff\",\n        },\n    },\n    {\n        ListView,\n        id = 'listview2',\n        layout_width = \"match\",\n        layout_height = \"match\",\n        visibility = \"gone\",\n    },\n    {\n        ListView,\n        id = 'listview',\n        layout_width = \"match\",\n        layout_height = \"match\",\n    },\n}\n\n\nlocal showCityData = false\n\nlocal item_view = {\n    TextView,\n    id = \"tv_name\",\n    gravity = \"center_vertical\",\n    layout_width = \"fill\",\n    layout_height = \"56dp\",\n    paddingLeft = \"16dp\",\n    textColor = \"#666666\",\n}\n\nlocal filePath = luajava.luaextdir .. '/weather/id'\nlocal data = {}\nlocal cityData = {}\n\nlocal function clearTable(t)\n    for k in pairs(t) do\n        t[k] = nil\n    end\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0xFF8CCACE)\n    activity.setContentView(loadlayout(layout))\n\n    for k, _ in pairs(China) do\n        data[#data + 1] = k\n    end\n\n    local adapter2 = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n        getCount = function() return #cityData end,\n        getView = function(position, convertView, parent)\n            position = position + 1 -- lua 索引从 1开始\n            if convertView == nil then\n                local views = {} -- store views\n                convertView = loadlayout(item_view, views, ListView)\n                convertView.getLayoutParams().width = parent.getWidth()\n                convertView.setTag(views)\n            end\n            local views = convertView.getTag()\n            local item = cityData[position]\n            views.tv_name.setText(item[2])\n            return convertView\n        end\n    }))\n    listview2.setAdapter(adapter2)\n    listview2.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n        onItemClick = function(adapter, view, position, id)\n            activity.toast('请稍候...')\n            position = position + 1\n            local id = cityData[position][1]:sub(2)\n            filehelper.writefile(filePath, id)\n            view.postDelayed(luajava.createProxy('java.lang.Runnable', {\n                run = function()\n                    activity.finish()\n                end\n            }), 500)\n        end,\n    }))\n\n    local adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n        getCount = function() return #data end,\n        getView = function(position, convertView, parent)\n            position = position + 1 -- lua 索引从 1开始\n            if convertView == nil then\n                local views = {} -- store views\n                convertView = loadlayout(item_view, views, ListView)\n                if parent then convertView.getLayoutParams().width = parent.getWidth() end\n                convertView.setTag(views)\n            end\n            local views = convertView.getTag()\n            local item = data[position]\n            print(position, item)\n            print(views.tv_name)\n            views.tv_name.setText(item)\n            return convertView\n        end\n    }))\n    listview.setAdapter(adapter)\n    listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n        onItemClick = function(adapter, view, position, id)\n            position = position + 1\n            local sTable = China[data[position]]\n            clearTable(cityData)\n            for k, v in pairs(sTable) do\n                for k2, v2 in pairs(v) do\n                    local name = k .. ' · ' .. v2\n                    if k == v2 then\n                        name = k\n                    end\n                    cityData[#cityData + 1] = { k2, name }\n                end\n            end\n            listview2.setVisibility(0)\n            listview.setVisibility(8)\n            adapter2.notifyDataSetChanged()\n            showCityData = true\n        end,\n    }))\nend\n\nfunction onBackPressed()\n    if showCityData then\n        listview2.setVisibility(8)\n        listview.setVisibility(0)\n        showCityData = false\n        return true\n    end\n    return false\nend\n"
  },
  {
    "path": "lua/weather/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaDrawable\"\nimport \"androlua.LuaView\"\nimport \"android.graphics.Paint\"\nimport \"androlua.LuaUtil\"\n\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\nlocal filehelper = require(\"filehelper\")\nlocal weather = require(\"weather.weather\")\nlocal log = require(\"log\")\n\nlocal item_hour = {\n    LinearLayout,\n    layout_weight = 1,\n    orientation = \"vertical\",\n    gravity = \"center\",\n    paddingTop = \"16dp\",\n    paddingBottom = \"16dp\",\n    {\n        TextView,\n        textSize = \"13sp\",\n        textColor = \"#666666\",\n        text = \"00:00\",\n    },\n    {\n        ImageView,\n        layout_width = \"match\",\n        layout_height = \"24dp\",\n        layout_marginBottom = \"4dp\",\n        layout_marginTop = \"12dp\",\n    },\n    {\n        TextView,\n        textSize = \"12sp\",\n        textColor = \"#666666\",\n        text = \"0°\",\n    },\n}\nlocal item_week = {\n    LinearLayout,\n    layout_weight = 1,\n    orientation = \"vertical\",\n    gravity = \"center\",\n    paddingTop = \"16dp\",\n    paddingBottom = \"16dp\",\n    {\n        TextView,\n        textSize = \"13sp\",\n        textColor = \"#666666\",\n        text = \"今天\",\n    },\n    {\n        ImageView,\n        layout_width = \"match\",\n        layout_height = \"24dp\",\n        layout_marginBottom = \"4dp\",\n        layout_marginTop = \"16dp\",\n    },\n    {\n        TextView,\n        textSize = \"10sp\",\n        textColor = \"#666666\",\n        text = \"多云\",\n    },\n}\n\n-- create view table\nlocal layout = {\n    ScrollView,\n    {\n        LinearLayout,\n        orientation = \"vertical\",\n        {\n            LinearLayout,\n            background = \"#8CCACE\",\n            layout_width = \"fill\",\n            layout_height = \"wrap\",\n            orientation = \"vertical\",\n            gravity = \"center_horizontal\",\n            {\n                RelativeLayout,\n                layout_width = \"fill\",\n                layout_height = \"56dp\",\n                layout_marginTop = \"25dp\",\n                {\n                    TextView,\n                    id = \"tv_city\",\n                    layout_height = \"match\",\n                    gravity = \"center\",\n                    layout_centerVertical = true,\n                    textSize = \"16sp\",\n                    textColor = \"#ffffff\",\n                    paddingLeft = \"16dp\",\n                    paddingRight = \"16dp\",\n                },\n                {\n                    TextView,\n                    layout_marginRight = \"16dp\",\n                    id = \"tv_update\",\n                    layout_alignParentRight = true,\n                    layout_centerVertical = true,\n                    textSize = \"12sp\",\n                    textColor = \"#aaffffff\",\n                },\n            },\n            {\n                LinearLayout,\n                layout_width = \"fill\",\n                orientation = \"vertical\",\n                gravity = \"center_horizontal\",\n                paddingBottom = \"72dp\",\n                paddingTop = \"24dp\",\n                {\n                    TextView,\n                    id = \"tv_weather\",\n                    textSize = \"18sp\",\n                    textColor = \"#eeffffff\",\n                },\n                {\n                    TextView,\n                    id = \"tv_temp\",\n                    layout_marginTop = \"8dp\",\n                    layout_marginBottom = \"12dp\",\n                    textSize = \"82sp\",\n                    textColor = \"#f1ffffff\",\n                },\n                {\n                    TextView,\n                    id = \"tv_wind\",\n                    textSize = \"13sp\",\n                    textColor = \"#aaffffff\",\n                },\n            },\n        },\n        {\n            LinearLayout,\n            id = \"layout_week\",\n            layout_width = \"fill\",\n            orientation = \"horizontal\",\n            item_week,\n            item_week,\n            item_week,\n            item_week,\n            item_week,\n            item_week,\n        },\n        {\n            LuaView,\n            id = \"line_view\",\n            layout_width = \"fill\",\n            layout_height = \"80dp\",\n        },\n        {\n            LinearLayout,\n            id = \"layout_24h\",\n            layout_width = \"fill\",\n            orientation = \"horizontal\",\n            item_hour,\n            item_hour,\n            item_hour,\n            item_hour,\n            item_hour,\n            item_hour,\n        },\n    },\n}\n\n-- bg http://i.tq121.com.cn/i/wap2016/news/d11.jpg\nlocal weekTemp = {}\n\nlocal function safeRun(f)\n    pcall(function()\n        f()\n    end)\nend\n\nlocal function fillBaseInfo(body)\n    local json = JSON.decode(string.match(body, '{.*}'))\n    tv_city.setText(json.cityname)\n    tv_temp.setText(json.temp .. '°')\n    tv_update.setText(json.time .. ' 更新')\n    tv_weather.setText(json.weather)\n    tv_wind.setText(string.format('空气指数 %s  •  %s  •  湿度 %s', json.aqi_pm25, json.WD .. ' ' .. json.WS, json.SD))\nend\n\n\n\nlocal function fillWeekInfo(body)\n    local json = JSON.decode(string.match(body, '{.*}'))\n    for i = 1, #json.f do\n        local child = layout_week.getChildAt(i - 1)\n        child.getChildAt(0).setText(json.f[i].fj)\n        local xmlPath = string.format('%s/weather/img/line_%s.png', luajava.luaextdir, json.f[i].fa)\n        child.getChildAt(1).setImageDrawable(LuaDrawable.create(xmlPath))\n        child.getChildAt(2).setText(weather['_' .. json.f[i].fa])\n        weekTemp[i] = { json.f[i].fc, json.f[i].fd }\n    end\n    line_view.invalidate()\nend\n\nlocal function fill24HInfo(body)\n    print(body)\n    local json = JSON.decode(string.match(body, 'fc1h_24%s+=(.*);'))\n    local j = 0\n    for i = 1, #json.jh, 3 do\n        local child = layout_24h.getChildAt(j)\n        if child then\n            child.getChildAt(0).setText(json.jh[i].jf:sub(9, 10) .. ':00')\n            local xmlPath = string.format('%s/weather/img/line_%s.png', luajava.luaextdir, json.jh[i].ja)\n            child.getChildAt(1).setImageDrawable(LuaDrawable.create(xmlPath))\n            child.getChildAt(2).setText(json.jh[i].jb .. '°')\n        end\n        j = j + 1\n    end\nend\n\n\n\nlocal function getData(url, successFunc)\n    print(url)\n    local options = {\n        url = url,\n        headers = {\n            \"Referer:http://m.weather.com.cn\"\n        }\n    }\n    LuaHttp.request(options, function(error, code, body)\n        if error or code ~= 200 then\n            print('fetch data error')\n            return\n        end\n        uihelper.runOnUiThread(activity, function()\n            successFunc(body)\n        end)\n    end)\nend\n\nlocal filePath = luajava.luaextdir .. '/weather/id'\n\nlocal function fetchData(id)\n    if id == nil then return end\n    getData(string.format('http://d1.weather.com.cn/sk_2d/%s.html', id), fillBaseInfo)\n    getData(string.format('http://d1.weather.com.cn/weixinfc/%s.html', id), fillWeekInfo)\n    getData(string.format('http://d1.weather.com.cn/wap_40d/%s.html', id), fill24HInfo)\nend\n\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x00000000)\n    activity.setContentView(loadlayout(layout))\n    local paint = Paint(1)\n    paint.setColor(0xFF666666)\n    paint.setTextSize(uihelper.dp2px(10))\n    paint.setStrokeWidth(uihelper.dp2px(1.5))\n    local linePaint1 = Paint(paint)\n    linePaint1.setColor(0xFFFFD139)\n    local linePaint2 = Paint(paint)\n    linePaint2.setColor(0xFF7FDCEF)\n\n    local radius = uihelper.dp2px(2.5)\n    local texWidth = uihelper.dp2px(6)\n\n    line_view.setCreator(luajava.createProxy('androlua.LuaView$Creator', {\n        onDraw = function(canvas)\n            local count = #weekTemp\n            local max = -999\n            local min = 999\n            for i = 1, count do\n                if tonumber(weekTemp[i][1]) > max then max = tonumber(weekTemp[i][1]) end\n                if tonumber(weekTemp[i][2]) < min then min = tonumber(weekTemp[i][2]) end\n            end\n            local dx = line_view.getWidth() / count\n            local startY = uihelper.dp2px(18)\n            local dy = (line_view.getHeight() - line_view.getPaddingTop() - line_view.getPaddingBottom() - startY - startY) / (max - min)\n            local lastPoint1 = {}\n            local lastPoint2 = {}\n            for i = 1, count do\n                local maxT = weekTemp[i][1]\n                local minT = weekTemp[i][2]\n                local x = dx * (i - 0.5)\n                local y1 = startY + (max - maxT) * dy\n                local y2 = startY + (max - minT) * dy\n                canvas.drawText(maxT .. '°', x - texWidth, y1 - texWidth, paint)\n                canvas.drawText(minT .. '°', x - texWidth, y2 + texWidth + texWidth, paint)\n                canvas.drawCircle(x, y1, radius, linePaint1)\n                canvas.drawCircle(x, y2, radius, linePaint2)\n                if lastPoint1[1] and lastPoint1[2] then\n                    canvas.drawLine(lastPoint1[1], lastPoint1[2], x, y1, linePaint1)\n                end\n\n                if lastPoint2[1] and lastPoint2[2] then\n                    canvas.drawLine(lastPoint2[1], lastPoint2[2], x, y2, linePaint2)\n                end\n\n\n                lastPoint1[1] = x\n                lastPoint1[2] = y1\n\n                lastPoint2[1] = x\n                lastPoint2[2] = y2\n            end\n        end,\n    }))\n\n    tv_city.onClick = function(v)\n        local intent = Intent(activity, LuaActivity)\n        intent.putExtra(\"luaPath\", 'weather/list_city.lua')\n        activity.startActivity(intent)\n    end\nend\n\n\nfunction onDestroy()\n    LuaHttp.cancelAll()\nend\n\nlocal function findCityCode(province, city)\n    local China = require(\"weather.city\")\n    for k, v in pairs(China) do\n        if province == k then\n            for k2, v2 in pairs(v) do\n                if k2 == city then\n                    print(city)\n                    log.print_r(v2) \n                    for k3,v3 in pairs(v2) do\n                        if(v3 == city) then\n                            return k3:sub(2)\n                        end\n                    end\n                end\n            end\n        end\n    end\n    return '101010100'\nend\n\nlocal function locateMe()\n    local id = '101010100'\n    local options = {\n        url = 'http://ip.taobao.com/service/getIpInfo2.php',\n        method = \"POST\",\n        formData = {\n            \"ip:myip\"\n        }\n    }\n    LuaHttp.request(options, function(error, code, body)\n        print(body)\n        if error or code ~= 200 then\n            print('locate failure')\n            return\n        end\n        local json = JSON.decode(body)\n        local province = json.data.region\n        local city = json.data.city\n        local county = json.data.county\n        local p = string.match(province, '(.*)省')\n        if p then province = p\n        else\n            p = string.match(province, '(.*)市')\n            if p then province = p end\n        end\n\n        local c = string.match(province, '(.*)市')\n        if c then city = c end\n\n        local id = findCityCode(province, city)\n        filehelper.writefile(filePath, id)\n        fetchData(id)\n    end)\nend\n\nfunction onResume()\n    safeRun(function()\n        local id = filehelper.readfile(filePath)\n        if id == nil then\n            locateMe()\n        else\n            fetchData(id)\n        end\n    end)\nend\n"
  },
  {
    "path": "lua/weather/weather.lua",
    "content": "return {\n    _00 = \"晴\",\n    _01 = \"多云\",\n    _02 = \"阴\",\n    _03 = \"阵雨\",\n    _04 = \"雷阵雨\",\n    _05 = \"雷阵雨伴有冰雹\",\n    _06 = \"雨夹雪\",\n    _07 = \"小雨\",\n    _08 = \"中雨\",\n    _09 = \"大雨\",\n    _10 = \"暴雨\",\n    _11 = \"大暴雨\",\n    _12 = \"特大暴雨\",\n    _13 = \"阵雪\",\n    _14 = \"小雪\",\n    _15 = \"中雪\",\n    _16 = \"大雪\",\n    _17 = \"暴雪\",\n    _18 = \"雾\",\n    _19 = \"冻雨\",\n    _20 = \"沙尘暴\",\n    _21 = \"小到中雨\",\n    _22 = \"中到大雨\",\n    _23 = \"大到暴雨\",\n    _24 = \"暴雨到大暴雨\",\n    _25 = \"大暴雨到特大暴雨\",\n    _26 = \"小到中雪\",\n    _27 = \"中到大雪\",\n    _28 = \"大到暴雪\",\n    _29 = \"浮尘\",\n    _30 = \"扬沙\",\n    _31 = \"强沙尘暴\",\n    _32 = \"浓雾\",\n    _49 = \"强浓雾\",\n    _53 = \"霾\",\n    _54 = \"中度霾\",\n    _55 = \"重度霾\",\n    _56 = \"严重霾\",\n    _57 = \"大雾\",\n    _58 = \"特强浓雾\",\n    _99 = \"无\",\n    _301 = \"雨\",\n    _302 = \"雪\"\n}"
  },
  {
    "path": "lua/weibo-hot/info.json",
    "content": "{\n  \"id\": \"pub.hanks.weibo-hot\",\n  \"name\": \"微博\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b08590d2920037?w=150&h=150&f=png&s=3556\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.3\",\n  \"versionCode\": 4,\n  \"desc\": \"热门微博\"\n}\n"
  },
  {
    "path": "lua/weibo-hot/item_msg.lua",
    "content": "return {\n    LinearLayout,\n    layout_width = \"fill\",\n    paddingTop = \"16dp\",\n    orientation = \"vertical\",\n    background = \"@drawable/layout_selector_tran\",\n    -- head\n    {\n        FrameLayout,\n        layout_width = \"match\",\n        layout_height = \"36dp\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"16dp\",\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_width = \"36dp\",\n            layout_height = \"36dp\",\n            scaleType = \"centerCrop\"\n        },\n        {\n            TextView,\n            id = \"tv_username\",\n            layout_marginLeft = \"44dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            maxLines = \"1\",\n            ellipsize = \"end\",\n            textSize = \"14sp\",\n            textColor = \"#e86b0f\",\n        },\n        {\n            TextView,\n            id = \"tv_date\",\n            layout_gravity = \"bottom\",\n            layout_marginLeft = \"44dp\",\n            layout_width = \"fill\",\n            maxLines = \"1\",\n            textSize = \"11sp\",\n            textColor = \"#999999\",\n        },\n    },\n    -- content\n    {\n        TextView,\n        id = \"tv_content\",\n        layout_width = \"fill\",\n        layout_marginLeft = \"16dp\",\n        layout_marginRight = \"16dp\",\n        layout_marginTop = \"12dp\",\n        lineSpacingMultiplier = '1.3',\n        textSize = \"14sp\",\n        textColor = \"#222222\",\n    },\n    -- pictures\n    {\n        LuaNineGridView,\n        id = \"iv_nine_grid\",\n        layout_width = \"match\",\n        layout_height = \"200dp\",\n        gap = \"4dp\",\n        maxSize = 9,\n        visibility = \"gone\",\n        layout_marginTop = \"12dp\",\n        layout_marginLeft = \"16dp\",\n        layout_marginRight = \"16dp\",\n    },\n\n    -- video\n    {\n        FrameLayout,\n        id = \"layout_video\",\n        layout_width = \"match\",\n        layout_height = \"200dp\",\n        layout_marginTop = \"12dp\",\n        layout_marginLeft = \"16dp\",\n        layout_marginRight = \"16dp\",\n        visibility = 8,\n        {\n            ImageView,\n            id = \"iv_video\",\n            layout_width = \"match\",\n            layout_height = \"200dp\",\n            scaleType = \"centerCrop\"\n        },\n        {\n            View,\n            layout_height = \"match\",\n            layout_width = \"match\",\n            background = \"#66000000\",\n        },\n        {\n            ImageView,\n            layout_gravity = \"center\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            src = \"#weibo-hot/ic_video_play.png\",\n        },\n    },\n    -- foot\n    {\n        LinearLayout,\n        layout_width = \"match\",\n        layout_height = \"56dp\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"16dp\",\n        gravity = \"center_vertical\",\n        orientation = \"horizontal\",\n        {\n            ImageView,\n            layout_width = \"20dp\",\n            layout_height = \"20dp\",\n            src = \"#weibo-hot/ic_retweet.png\",\n        },\n        {\n            TextView,\n            id = \"tv_retweet\",\n            layout_width = \"70dp\",\n            paddingLeft = \"4dp\",\n            textSize = \"12sp\",\n            textColor = \"#A6A6A6\",\n        },\n        {\n            ImageView,\n            layout_width = \"20dp\",\n            layout_height = \"20dp\",\n            src = \"#weibo-hot/ic_comment.png\"\n        },\n        {\n            TextView,\n            id = \"tv_comment\",\n            paddingLeft = \"4dp\",\n            layout_width = \"70dp\",\n            textSize = \"12sp\",\n            textColor = \"#A6A6A6\",\n        },\n        {\n            ImageView,\n            layout_width = \"20dp\",\n            layout_height = \"20dp\",\n            src = \"#weibo-hot/ic_unlike.png\"\n        },\n        {\n            TextView,\n            id = \"tv_like\",\n            paddingLeft = \"4dp\",\n            layout_width = \"70dp\",\n            textSize = \"12sp\",\n            textColor = \"#A6A6A6\",\n        },\n    },\n    {\n        View,\n        layout_height = \"8dp\",\n        layout_width = \"fill\",\n        background = \"#e1e1e1\",\n    }\n}\n"
  },
  {
    "path": "lua/weibo-hot/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/29\n-- A zhihu daliy app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.view.View\"\nimport \"android.support.v4.widget.Space\"\nimport \"androlua.widget.ninegride.LuaNineGridView\"\nimport \"androlua.widget.ninegride.LuaNineGridViewAdapter\"\nimport \"androlua.widget.picture.PicturePreviewActivity\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.graphics.drawable.Drawable\"\nimport \"java.net.URL\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"android.net.Uri\"\nimport \"android.text.Html\"\nimport \"android.text.method.LinkMovementMethod\"\nimport \"androlua.LuaDrawable\"\nimport \"java.lang.Thread\"\n\nlocal JSON = require \"cjson\"\nlocal uihelper = require \"uihelper\"\n\n-- create view table\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"match\",\n    layout_height = \"match\",\n    orientation = \"vertical\",\n    fitsSystemWindows = true,\n    {\n        Toolbar,\n        background = '#ffffff',\n        id = 'toolbar',\n        layout_width = \"match\",\n        layout_height = \"56dp\",\n        elevation = \"2dp\",\n    },\n    {\n        SwipeRefreshLayout,\n        id = \"refreshLayout\",\n        layout_width = \"match\",\n        {\n            RecyclerView,\n            id = \"recyclerView\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n    },\n}\n\nlocal item_view = require \"weibo-hot/item_msg\"\nlocal adapter\nlocal data = {}\nlocal page = 1\n\nlocal function launchDetail(msg)\n    if msg and msg.mblog.id then\n        local url = 'https://m.weibo.cn/status/' .. msg.mblog.id\n        WebViewActivity.start(activity, url, 0xFFe86b0f)\n        return\n    end\n\n    activity.toast('没有 url 可以打开')\nend\n\nlocal function launchPicturePreview(msg, index)\n    local urls = {}\n    for i = 1, #msg.mblog.pics do\n        urls[i] = msg.mblog.pics[i].large.url\n    end\n    local data = {\n        uris = urls,\n        currentIndex = index\n    }\n    PicturePreviewActivity.start(activity, JSON.encode(data))\nend\n\nlocal function fetchData()\n    local url = \"https://m.weibo.cn/api/container/getIndex?containerid=102803_ctg1_9999_-_ctg1_9999&count=10&luicode=10000011&lfid=102803_ctg1_8999_-_ctg1_8999_home&page=\" .. page\n    if page < 2 then url = \"https://m.weibo.cn/api/container/getIndex?containerid=102803_ctg1_9999_-_ctg1_9999&count=10&luicode=10000011&lfid=102803_ctg1_8999_-_ctg1_8999_home\" end\n    local options = {\n        url = url\n    }\n    LuaHttp.request(options, function(error, code, body)\n        local cards = JSON.decode(body).data.cards\n        uihelper.runOnUiThread(activity, function()\n            if page == 0 then\n                for k, _ in pairs(data) do data[k] = nil end\n            end\n            local s = #data\n            for i = 1, #cards do\n                local item = cards[i]\n                if item.card_group then\n                    for j = 1, #item.card_group do\n                        data[#data + 1] = item.card_group[j]\n                    end\n                else\n                    data[#data + 1] = item\n                end\n            end\n            page = page + 1\n            adapter.notifyItemRangeChanged(s, #data)\n            refreshLayout.setRefreshing(false)\n        end)\n    end)\nend\n\n local imgGetter = luajava.createProxy('android.text.Html$ImageGetter', {\n    getDrawable = function(imgUrl) return LuaDrawable.create('weibo-hot/weibo_logo.png') end\n    -- getDrawable = function(imgUrl)\n    --     if not imgUrl:find('^http') then  imgUrl = 'https://' .. imgUrl end\n    --     Thread(luajava.createProxy('java.lang.Runnable',{\n    --         run = function()\n    --             local is = URL(imgUrl).getContent()\n    --             local drawable = Drawable.createFromStream(is,\"src\")\n    --             drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight())\n    --             is.close()\n    --         end\n    --     }).start()\n    --     local is = URL(imgUrl).getContent()\n    --     local drawable = Drawable.createFromStream(is,\"src\")\n    --     drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight())\n    --     is.close()\n    --     return drawable\n    -- end\n})\n\nfunction onCreate(savedInstanceState)\n    activity.setLightStatusBar()\n    activity.setContentView(loadlayout(layout))\n    activity.setSupportActionBar(toolbar)\n    activity.setTitle('热门微博')\n    toolbar.setNavigationIcon(LuaDrawable.create('weibo-hot/weibo_logo.png'))\n\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function() return #data end,\n        getItemViewType = function(position) return 0 end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.getLayoutParams().width = parent.getWidth()\n            holder.itemView.setTag(views)\n            holder.itemView.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1\n                launchDetail(data[position])\n            end\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local msg = data[position]\n            local views = holder.itemView.getTag()\n           \n            views.tv_username.setText(msg.mblog.user.screen_name or 'xxxxx')\n            views.tv_content.setText(Html.fromHtml(msg.mblog.text, imgGetter, nil))\n            -- views.tv_content.setMovementMethod(LinkMovementMethod.getInstance())\n            views.tv_date.setText(msg.mblog.created_at or '刚刚')\n            views.tv_retweet.setText(string.format('%d', msg.mblog.reposts_count))\n            views.tv_comment.setText(string.format('%d', msg.mblog.comments_count))\n            views.tv_like.setText(string.format('%d', msg.mblog.attitudes_count))\n            LuaImageLoader.loadWithRadius(views.iv_image, 40, msg.mblog.user.profile_image_url)\n            if msg.mblog.pics and #msg.mblog.pics > 0 then\n                local pictures = msg.mblog.pics\n                local urls = {}\n                local len = #pictures\n                for i = 1, len do\n                    if len == 1 then\n                        urls[i] = pictures[i].large.url\n                        local w = pictures[i].large.geo.width or 200\n                        local h = pictures[i].large.geo.height or 200\n                        views.iv_nine_grid.setSingleImgSize(tonumber(w), tonumber(h))\n                    else urls[i] = pictures[i].url\n                    end\n                end\n                views.iv_nine_grid.setVisibility(0)\n                views.iv_nine_grid.setAdapter(LuaNineGridViewAdapter(luajava.createProxy('androlua.widget.ninegride.LuaNineGridViewAdapter$AdapterCreator', {\n                    onDisplayImage = function(context, imageView, url)\n                        LuaImageLoader.load(imageView, url)\n                    end,\n                    onItemImageClick = function(context, imageView, index, list)\n                        launchPicturePreview(msg, index)\n                    end\n                })))\n                views.iv_nine_grid.setImagesData(urls)\n            else\n                views.iv_nine_grid.setVisibility(8)\n            end\n            if msg.mblog.page_info and msg.mblog.page_info.type == 'video' then\n                views.layout_video.setVisibility(0)\n                LuaImageLoader.load(views.iv_video, msg.mblog.page_info.page_pic.url)\n            else\n                views.layout_video.setVisibility(8)\n            end\n\n            if position == #data then fetchData() end\n        end,\n    }))\n    recyclerView.setLayoutManager(LinearLayoutManager(activity))\n    recyclerView.setAdapter(adapter)\n    refreshLayout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n        onRefresh = function()\n            page = 1\n            fetchData()\n        end\n    }))\n    refreshLayout.setRefreshing(true)\n    fetchData()\nend\n\nfunction onCreateOptionsMenu(menu)\n    menu.add(\"网页版\")\n    return true\nend\n\nfunction onOptionsItemSelected(item)\n    local title = item.getTitle()\n    if title == \"网页版\" then\n        activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse('http://m.weibo.cn')))\n    end\nend\n\n\n"
  },
  {
    "path": "lua/wikibaidu/info.json",
    "content": "{\n  \"id\": \"pub.hanks.wikibaidu\",\n  \"name\": \"百度百科\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b0859e82e896b5?w=150&h=150&f=png&s=3461\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 2,\n  \"desc\": \"中文知识性百科全书(需最新客户端)\"\n}\n"
  },
  {
    "path": "lua/wikibaidu/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- qiqu\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaWebView\"\nimport \"pub.hydrogen.android.BuildConfig\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    statusBarColor = \"#33000000\",\n    {\n        LuaWebView,\n        id = \"webview\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    }\n}\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    webview.loadUrl('https://wapbaike.baidu.com/')\n    if BuildConfig.VERSION_CODE < 15 then\n        activity.toast(\"氢应用版本太低，可能无法正常使用，请升级最新版本！\")\n    end\nend\n\nfunction onBackPressed()\n    if webview.canGoBack() then webview.goBack() return true end\n    return false\nend\n\nfunction onDestroy()\n    pcall(function( )\n        webview.release()\n    end)\nend\n"
  },
  {
    "path": "lua/yilin/activity_detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nlocal uihelper = require \"uihelper\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#66ae28\",\n    {\n        LinearLayout,\n        orientation = \"horizontal\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#66ae28\",\n        gravity = \"center_vertical\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginLeft = \"8dp\",\n            scaleType = \"centerInside\",\n            src = \"@drawable/ic_menu_back\",\n        },\n        {\n            TextView,\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            paddingRight = \"16dp\",\n            singleLine = true,\n            textIsSelectable = true,\n            ellipsize = \"end\",\n            id = \"tv_title\",\n            gravity = \"center_vertical\",\n            paddingLeft = \"8dp\",\n            textColor = \"#ffffff\",\n            textSize = \"14sp\",\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            LuaWebView,\n            id = \"webview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            ProgressBar,\n            layout_gravity = \"center\",\n            id = \"progressBar\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal css = [[\n    article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-webkit-text-size-adjust:100%}body{font-family:'Helvetica Neue',Helvetica,Arial,Sans-serif;background:#fff;padding-top:0;margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0}h1,h2,h3,h4,h5,h6{font-size:16px}abbr[title]{border-bottom:1px dotted}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:\\201C\\201D\\2018\\2019}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0;vertical-align:middle;color:transparent;font-size:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}table{border-collapse:collapse;border-spacing:0;overflow:hidden}a{text-decoration:none}blockquote{border-left:3px solid #d0e5f2;font-style:normal;display:block;vertical-align:baseline;font-size:100%;margin:.5em 0;padding:0 0 0 1em}ul,ol{padding-left:20px}.content{color:#444;line-height:1.6em;font-size:16px;margin:16px}.content img{max-width:100%;display:block;margin:30px auto}.content img+img{margin-top:15px}.content img[src*=\"zhihu.com/equation\"]{display:inline-block;margin:0 3px}.content a{color:#259}.content a:hover{text-decoration:underline}\n]]\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html>\n<head>\n    <title></title>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width; initial-scale=1; minimum-scale=1; maximum-scale=2\">\n    <meta content=\"width=device-width,user-scalable=no\" name=\"viewport\">\n    <style type=\"text/css\"> %s </style>\n</head>\n<body>\n<div class=\"content\"> %s </div>\n</body>\n</html>\n]]\n\n\n\nlocal function getData(url)\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local content = string.match(body, '<div class=\"blkContainerSblk collectionContainer\">(.-</div>)%s+<div class=\"center\">')\n        local data = string.format(htmlTemplate, css, content)\n        uihelper.runOnUiThread(activity, function()\n            print(data)\n            webview.loadData(data, \"text/html; charset=UTF-8\", nil)\n        end)\n    end)\nend\n\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    back.onClick = function()\n        activity.finish()\n    end\n    local url = activity.getIntent().getStringExtra('url')\n    tv_title.setText(url)\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    getData(url)\nend\n\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend\n"
  },
  {
    "path": "lua/yilin/fragment_yilin.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"java.lang.String\"\n\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\n\nlocal pageList = {}\n\n\nlocal function trim(s)\n    return s:gsub(\"^%s+\", \"\"):gsub(\"%s+$\", \"\")\nend\n\nlocal function getData(params, data, adapter, fragment, swipe_layout, reload)\n\n    local function getPageList()\n        LuaHttp.request({ url = 'http://www.92yilin.com/' }, function(error, code, body)\n            for booklist in string.gmatch(body, \"<table class='booklist'>(.-)</table>\") do\n                local arr = {}\n                for td in string.gmatch(booklist, '<td.-</td>') do\n                    if not td:find('colspan') then\n                        local url = string.match(td, \"<a href=.(.-).%s\")\n                        arr[#arr + 1] = url\n                    end\n                end\n                pageList[#pageList + 1] = arr\n            end\n            getData(params, data, adapter, fragment, swipe_layout, reload)\n        end)\n    end\n\n    if #pageList == 0 then\n        getPageList(params, data, adapter, fragment, swipe_layout, reload)\n        return\n    end\n\n    local list = pageList[params.id]\n    local pageUrl = 'http://www.92yilin.com/' .. list[params.page]\n    LuaHttp.request({ url = pageUrl }, function(error, code, body)\n        if error or code ~= 200 then return end\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            if reload then\n                for k, _ in pairs(data) do data[k] = nil end\n            end\n            for span in string.gmatch(body, \"<span.->.-</span>\") do\n                if span:find('maglisttitle') then\n                    local url, title = string.match(span, '<a .- href=\"(.-)\" title=\"(.-)\">')\n                    data[#data + 1] = { title = title, url = pageUrl:gsub('index.html', url) }\n                else\n                    local h2 = string.match(span, '<span.->(.-)</span>')\n                    h2 = trim(h2)\n                    data[#data + 1] = { h2 = h2 }\n                end\n            end\n            params.page = params.page + 1\n            adapter.notifyDataSetChanged()\n            swipe_layout.setRefreshing(false)\n            swipe_layout.setEnable(false)\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, item)\n    local activity = fragment.getActivity()\n    if item == nil or item.url == nil then\n        return\n    end\n\n    local activity = fragment.getActivity()\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'yilin/activity_detail.lua')\n    intent.putExtra(\"url\", '' .. item.url)\n    activity.startActivity(intent)\nend\n\nlocal function newInstance(id)\n\n    -- create view table\n    local layout = {\n        SwipeRefreshLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        id = \"swipe_layout\",\n        {\n            ListView,\n            id = \"listview\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        }\n    }\n\n    local item_view = {\n        LinearLayout,\n        layout_width = \"fill\",\n        layout_height = \"wrap\",\n        orientation = \"vertical\",\n        {\n            TextView,\n            id = \"tv_h1\",\n            layout_height = \"40dp\",\n            layout_width = \"fill\",\n            paddingLeft = \"16dp\",\n            gravity = \"center_vertical\",\n            textSize = \"14sp\",\n            visibility = \"gone\",\n            background = \"#eef1f6\",\n            textColor = \"#1f2d3d\",\n        },\n        {\n            TextView,\n            id = \"tv_title\",\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            paddingLeft = \"16dp\",\n            paddingRight = \"16dp\",\n            singleLine = true,\n            ellipsize = \"end\",\n            gravity = \"center_vertical\",\n            textSize = \"14sp\",\n            textColor = \"#1f2d3d\",\n        }\n    }\n\n    local hadLoadData\n    local isVisible\n    local data = {}\n    local params = { id = id, page = 1 }\n    local ids = {}\n    local adapter\n    local fragment = LuaFragment.newInstance()\n    local function lazyLoad()\n        if not isVisible then return end\n        if hadLoadData then return end\n        if adapter == nil then return end\n        hadLoadData = true\n        getData(params, data, adapter, fragment, ids.swipe_layout)\n    end\n\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        convertView.getLayoutParams().width = parent.getWidth()\n                        convertView.setTag(views)\n                    end\n                    local views = convertView.getTag()\n                    local item = data[position]\n                    if item then\n                        if item.h2 then\n                            views.tv_h1.setVisibility(0)\n                            views.tv_title.setVisibility(8)\n                            views.tv_h1.setText(item.h2 or '意林')\n                        else\n                            views.tv_h1.setVisibility(8)\n                            views.tv_title.setVisibility(0)\n                            views.tv_title.setText(' · ' .. item.title)\n                        end\n                    end\n\n                    if position == #data then\n                        getData(params, data, adapter, fragment, ids.swipe_layout)\n                    end\n\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    launchDetail(fragment, data[position + 1])\n                end,\n            }))\n            ids.swipe_layout.setRefreshing(true)\n            ids.swipe_layout.setOnRefreshListener(luajava.createProxy('android.support.v4.widget.SwipeRefreshLayout$OnRefreshListener', {\n                onRefresh = function()\n                    getData(params, data, adapter, fragment, ids.swipe_layout, true)\n                end\n            }))\n            lazyLoad()\n        end,\n        onUserVisible = function(visible)\n            isVisible = visible\n            lazyLoad()\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/yilin/info.json",
    "content": "{\n  \"id\": \"pub.hanks.yilin\",\n  \"name\": \"意林\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b08862dca86462?w=150&h=150&f=png&s=3415\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.1\",\n  \"versionCode\": 3,\n  \"desc\": \"《意林》杂志，鸡汤慎重服用\"\n}\n"
  },
  {
    "path": "lua/yilin/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\n\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\nlocal fragmentNews = require \"yilin/fragment_yilin\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#66ae28\",\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#66ae28\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\n\ntable.insert(data.fragments, fragmentNews.newInstance(1))\ntable.insert(data.titles, '意林')\n\ntable.insert(data.fragments, fragmentNews.newInstance(2))\ntable.insert(data.titles, '作文素材')\n\ntable.insert(data.fragments, fragmentNews.newInstance(3))\ntable.insert(data.titles, '少年版')\n\ntable.insert(data.fragments, fragmentNews.newInstance(4))\ntable.insert(data.titles, '原创版')\n\ntable.insert(data.fragments, fragmentNews.newInstance(5))\ntable.insert(data.titles, '12+')\n\n\nlocal adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nfunction onCreate(savedInstanceState)\n\n    activity.setContentView(loadlayout(layout))\n    viewPager.setAdapter(adapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\n    tab.setSelectedTabIndicatorColor(0xffffffff)\n    tab.setTabTextColors(0x88ffffff, 0xffffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\nend\n"
  },
  {
    "path": "lua/zhihu-recommend/info.json",
    "content": "{\n  \"id\": \"pub.hanks.zhihu-recommend\",\n  \"name\": \"知乎热门\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b08868307f7ea6?w=150&h=150&f=png&s=2168\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0.1\",\n  \"versionCode\": 3,\n  \"desc\": \"知乎热门推荐\"\n}\n"
  },
  {
    "path": "lua/zhihu-recommend/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- douban - hot movie\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.widget.video.VideoPlayerActivity\"\nimport \"androlua.LuaImageLoader\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.LinearLayoutManager\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"android.net.Uri\"\nimport \"pub.hydrogen.android.R\"\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\nlocal log = require(\"log\")\nactivity.setTheme(R.style.Theme_AppCompat_NoActionBar)\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    statusBarColor = \"#0077D9\",\n    {\n        Toolbar,\n        background = '#0077D9',\n        id = 'toolbar',\n        layout_width = \"match\",\n        layout_height = \"56dp\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            RecyclerView,\n            background = \"#f1f1f1\",\n            id = \"recyclerView\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal item_view = {\n    LinearLayout,\n    orientation = 'vertical',\n    layout_width = \"match\",\n    {\n        LinearLayout,\n        orientation = 'vertical',\n        layout_width = \"match\",\n        background = \"@drawable/layout_selector_tran\",\n        padding = \"16dp\",\n        {\n            LinearLayout,\n            id = 'layout_user',\n            gravity = 'center_vertical',\n            {\n                ImageView,\n                id = \"iv_avatar\",\n                layout_width = \"20dp\",\n                layout_height = \"20dp\",\n                scaleType = \"centerCrop\",\n            },\n            {\n                TextView,\n                layout_width = \"match\",\n                id = \"tv_user\",\n                gravity = \"center_vertical\",\n                paddingLeft = \"8dp\",\n                textSize = \"12sp\",\n                maxLines = 1,\n                ellipsize = \"end\",\n                textColor = \"#929EA5\",\n            },\n        },\n        {\n            TextView,\n            id = \"tv_title\",\n            layout_width = \"match\",\n            paddingTop = \"8dp\",\n            textSize = \"16sp\",\n            textColor = \"#212121\",\n        },\n        {\n            TextView,\n            id = \"tv_summary\",\n            layout_width = \"match\",\n            paddingTop = \"8dp\",\n            lineSpacingMultiplier = 1.2,\n            maxLines = 5,\n            textSize = \"14sp\",\n            textColor = \"#343434\",\n        },\n        {\n            TextView,\n            id = \"tv_info\",\n            layout_width = \"match\",\n            paddingTop = \"8dp\",\n            maxLines = 1,\n            textSize = \"12sp\",\n            textColor = \"#919DA4\",\n        },\n    },\n\n    {\n        View,\n        layout_width = \"match\",\n        layout_height = \"8dp\",\n        background = '#E1E6EB',\n    },\n}\n\nlocal data = {}\nlocal adapter\nlocal page = 0\n\nfunction trim(s)\n    if s == nil then return '' end\n    return s:gsub('<.->', ''):gsub('\\\\n', ''):gsub('^%s+', ''):gsub('%s+$', '')\nend\n\nlocal function getData()\n    local url = string.format('https://www.zhihu.com/node/ExploreRecommendListV2')\n    local options = {\n        url = url,\n        method = 'POST',\n        formData = { \"method:next\", 'params:{\"limit\":20,\"offset\":' .. page * 20 .. '}' }\n    }\n    LuaHttp.request(options, function(error, code, body)\n        if error or code ~= 200 then\n            print('fetch data error')\n            return\n        end\n        page = page + 1\n        local msg = JSON.decode(body).msg\n        uihelper.runOnUiThread(activity, function()\n            local s = #data\n            for i = 1, #msg do\n                local item = msg[i]:gsub('\\\\\"', '\"')\n                local title, url = string.match(item, '<h2>(.-href=\"(.-)\".-)</h2>')\n                local likeCount = string.match(item, '<div class=\"zm[-]item[-]vote\">(.-)</div>')\n                local username = string.match(item, 'class=\"author[-]link\".-</a>') or ''\n                if username then username = '<' .. username end\n                local desc = string.match(item, '<span.-class=\"bio\">(.-)</span>')\n                local summary = string.match(item, '<div.-class=\"zh[-]summary.->(.-)</div>')\n                local commentCount = string.match(item, 'name=\"addcomment\".->(.-)</a>')\n                local avatar = string.match(item, '<img.-src=\"(.-)\".-class=\"zm[-]list[-]avatar.-\">')\n                data[#data + 1] = {\n                    url = trim(url),\n                    title = trim(title),\n                    avatar = trim(avatar),\n                    username = trim(username),\n                    desc = trim(desc),\n                    summary = trim(summary),\n                    likeCount = trim(likeCount),\n                    commentCount = trim(commentCount)\n                }\n            end\n            adapter.notifyItemRangeChanged(s, #data)\n        end)\n    end)\nend\n\nlocal function launchDetail(item)\n    import \"androlua.widget.webview.WebViewActivity\"\n    if item and item.url then\n        local url = item.url\n        if not url:find('^http') then url = 'https://www.zhihu.com' .. url end\n        WebViewActivity.start(activity, url, 0xFF0077D9)\n        return\n    end\n    activity.toast('没有 url 可以打开')\nend\n\nfunction onDestroy()\n    LuaHttp.cancelAll()\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    activity.setSupportActionBar(toolbar)\n    activity.setTitle('热门精选')\n    toolbar.setNavigationIcon(LuaDrawable.create('zhihu-recommend/zhihu.png'))\n    local screenWidth = uihelper.getScreenWidth()\n    adapter = LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n        getItemCount = function()\n            return #data\n        end,\n        getItemViewType = function(position)\n            return 0\n        end,\n        onCreateViewHolder = function(parent, viewType)\n            local views = {}\n            local holder\n            holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n            holder.itemView.setTag(views)\n            holder.itemView.onClick = function(view)\n                local position = holder.getAdapterPosition() + 1\n            end\n            holder.itemView.getLayoutParams().width = screenWidth\n            holder.itemView.onClick = function()\n                local p = holder.getAdapterPosition() + 1\n                launchDetail(data[p])\n            end\n            views.tv_title.setTypeface(nil, 1);\n            return holder\n        end,\n        onBindViewHolder = function(holder, position)\n            position = position + 1\n            local views = holder.itemView.getTag()\n            if views == nil then return end\n            local item = data[position]\n            LuaImageLoader.loadWithRadius(views.iv_avatar, 20, item.avatar)\n            if item.username == '' or item.username == '<' then\n                views.layout_user.setVisibility(8)\n            else\n                views.layout_user.setVisibility(0)\n                views.tv_user.setText(string.format('%s  %s', item.username, item.desc))\n            end\n            views.tv_title.setText(item.title)\n            views.tv_summary.setText(item.summary)\n            views.tv_info.setText(string.format('%d 赞同  %s', item.likeCount, item.commentCount))\n            if position == #data then\n                getData()\n            end\n        end,\n    }))\n    recyclerView.setLayoutManager(LinearLayoutManager(activity))\n    recyclerView.setAdapter(adapter)\n    getData()\nend\n\n\nfunction onCreateOptionsMenu(menu)\n    menu.add(\"网页版\")\n    return true\nend\n\nfunction onOptionsItemSelected(item)\n    local title = item.getTitle()\n    if title == \"网页版\" then\n        activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse('https://www.zhihu.com/explore')))\n    end\nend"
  },
  {
    "path": "lua/zhihudaliy/activity_zhihu_daliy_detail.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/26\n-- A news app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"androlua.LuaWebView\"\nimport \"androlua.LuaHttp\"\nlocal uihelper = require(\"uihelper\")\nlocal JSON = require(\"cjson\")\n-- create view table\nlocal layout = {\n    FrameLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        LuaWebView,\n        id = \"webview\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n    {\n        ProgressBar,\n        layout_gravity = \"center\",\n        id = \"progressBar\",\n        layout_width = \"40dp\",\n        layout_height = \"40dp\",\n    },\n}\n\nlocal htmlTemplate = [[\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"user-scalable=no, width=device-width\">\n    <title>%s</title>\n    <style>\n    .img-place-holder{\n        background-image: url(%s);\n        background-size: cover;\n        position: relative;\n    }\n    </style>\n    %s\n</head>\n<body>%s</body>\n</html>\n]]\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0x00000000)\n    activity.setContentView(loadlayout(layout))\n    local id = activity.getIntent().getStringExtra('newsid')\n    webview.setVisibility(0)\n    progressBar.setVisibility(8)\n    LuaHttp.request({ url = string.format('http://news-at.zhihu.com/api/4/news/%d', id) }, function(error, code, body)\n        local json = JSON.decode(body)\n        local title = json.title or ''\n        local body = json.body or ''\n        local image = json.image or 'https://pic1.zhimg.com/v2-456bb69183a78a7290c64ad7580fa2ec.jpg'\n        local css = ''\n        if json.css then\n            for i = 1, #json.css do\n                css = css .. string.format('<link rel=\"stylesheet\" href=\"%s\"', json.css[i])\n            end\n        end\n\n        local data = string.format(htmlTemplate, title, image, css, body)\n        uihelper.runOnUiThread(activity, function()\n            webview.loadData(data, \"text/html; charset=UTF-8\", nil)\n        end)\n    end)\nend\n\n\nfunction onDestroy()\n    if webview then\n        webview.getParent().removeView(webview)\n        webview.destroy()\n        webview = nil\n    end\nend"
  },
  {
    "path": "lua/zhihudaliy/fragment_zhihu_daliy.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaImageLoader\"\n\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\n\nlocal function fetchData(id, data, adapter, fragment)\n    local url\n    if id then url = string.format('http://news-at.zhihu.com/api/4/theme/%d', id)\n    else\n        url = string.format('http://news.at.zhihu.com/api/4/news/before/%s', data.lastPage)\n    end\n\n    LuaHttp.request({ url = url }, function(error, code, body)\n        local json = JSON.decode(body)\n        if json.date then data.lastPage = json.date end\n        local stories = json.stories\n        for i = 1, #stories do\n            local item = {}\n            item.type = stories[i].type\n            item.id = stories[i].id\n            item.title = stories[i].title\n            item.images = stories[i].images\n            data.news[#data.news + 1] = item\n        end\n        uihelper.runOnUiThread(fragment.getActivity(), function()\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nlocal function launchDetail(fragment, newsid)\n    local activity = fragment.getActivity()\n    local intent = Intent(activity, LuaActivity)\n    intent.putExtra(\"luaPath\", 'zhihudaliy/activity_zhihu_daliy_detail.lua')\n    intent.putExtra(\"newsid\", string.format('%d', newsid))\n    activity.startActivity(intent)\nend\n\nfunction newInstance(id)\n\n    -- create view table\n    local layout = {\n        ListView,\n        id = \"listview\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    }\n\n    local item_view = {\n        RelativeLayout,\n        layout_height = \"wrap\",\n        paddingLeft = \"16dp\",\n        paddingRight = \"12dp\",\n        paddingTop = \"16dp\",\n        paddingBottom = \"16dp\",\n        {\n            ImageView,\n            id = \"iv_image\",\n            layout_alignParentRight = true,\n            layout_width = \"72dp\",\n            layout_height = \"72dp\",\n        },\n        {\n            TextView,\n            id = \"tv_title\",\n            paddingRight = \"16dp\",\n            maxLines = \"2\",\n            layout_alignParentLeft = true,\n            lineSpacingMultiplier = '1.3',\n            textSize = \"14sp\",\n            textColor = \"#222222\",\n            layout_toLeftOf = \"iv_image\",\n        },\n    }\n\n    local data = {\n        news = {},\n        lastPage = '99990101',\n    }\n    local ids = {}\n\n    local fragment = LuaFragment.newInstance()\n    local adapter\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onDestroyView = function() end,\n        onDestroy = function() end,\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n                getCount = function() return #data.news end,\n                getItem = function(position) return nil end,\n                getItemId = function(position) return position end,\n                getView = function(position, convertView, parent)\n                    position = position + 1 -- lua 索引从 1开始\n                    if position == #data.news then\n                        if id == nil then\n                            fetchData(id, data, adapter, fragment)\n                        end\n                    end\n                    if convertView == nil then\n                        local views = {} -- store views\n                        convertView = loadlayout(item_view, views, ListView)\n                        if parent then\n                            local params = convertView.getLayoutParams()\n                            params.width = parent.getWidth()\n                        end\n                        convertView.setTag(views)\n                    end\n                    local views = convertView.getTag()\n                    local item = data.news[position]\n                    if item then\n                        if item.images and #item.images[1] then\n                            views.iv_image.setVisibility(0)\n                            LuaImageLoader.load(views.iv_image, item.images[1])\n                        else views.iv_image.setVisibility(8)\n                        end\n                        views.tv_title.setText(item.title)\n                    end\n                    return convertView\n                end\n            }))\n            ids.listview.setAdapter(adapter)\n            ids.listview.setOnItemClickListener(luajava.createProxy(\"android.widget.AdapterView$OnItemClickListener\", {\n                onItemClick = function(adapter, view, position, id)\n                    local newsid = data.news[position + 1].id\n                    launchDetail(fragment, newsid)\n                end,\n            }))\n            fetchData(id, data, adapter, fragment) -- getdata may call ther lua files\n        end,\n    }))\n    return fragment\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua/zhihudaliy/info.json",
    "content": "{\n  \"id\": \"pub.hanks.zhihudaliy\",\n  \"name\": \"知乎日报\",\n  \"icon\": \"https://user-gold-cdn.xitu.io/2019/5/30/16b0885a8fec1499?w=150&h=150&f=png&s=2441\",\n  \"main\": \"main.lua\",\n  \"versionName\": \"1.0\",\n  \"versionCode\": 3,\n  \"desc\": \"提取知乎日报内容\"\n}\n"
  },
  {
    "path": "lua/zhihudaliy/main.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/29\n-- A zhihu daliy app\n--\nrequire \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\nimport \"androlua.LuaHttp\"\n\nlocal JSON = require \"cjson\"\nlocal uihelper = require \"uihelper\"\nlocal fragment = require \"zhihudaliy/fragment_zhihu_daliy\"\n\n-- create view table\nlocal layout = {\n    LinearLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    orientation = \"vertical\",\n    statusBarColor = \"#16A0EA\",\n    {\n        TabLayout,\n        id = \"tab\",\n        layout_width = \"fill\",\n        layout_height = \"48dp\",\n        background = \"#16A0EA\",\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        {\n            ViewPager,\n            id = \"viewPager\",\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n        },\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    }\n}\n\nlocal data = {\n    titles = {},\n    fragments = {},\n}\n\nlocal adapter\n\nlocal function getData()\n    LuaHttp.request({ url = \"http://news-at.zhihu.com/api/4/themes\" }, function(error, code, body)\n        local themes = JSON.decode(body).others\n        uihelper.runOnUiThread(activity, function()\n            for i = 1, #themes do\n                table.insert(data.titles, themes[i].name)\n                table.insert(data.fragments, fragment.newInstance(themes[i].id))\n            end\n            adapter.notifyDataSetChanged()\n        end)\n    end)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setStatusBarColor(0xff16A0EA)\n    activity.setContentView(loadlayout(layout))\n\n    table.insert(data.fragments, fragment.newInstance())\n    table.insert(data.titles, '首页')\n\n    adapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n        luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n            getCount = function() return #data.fragments end,\n            getItem = function(position)\n                position = position + 1\n                return data.fragments[position]\n            end,\n            getPageTitle = function(position)\n                position = position + 1\n                return data.titles[position]\n            end\n        }))\n    viewPager.setAdapter(adapter)\n    tab.setSelectedTabIndicatorColor(0xffffffff)\n    tab.setTabTextColors(0x88ffffff, 0xffffffff)\n    tab.setTabMode(TabLayout.MODE_SCROLLABLE)\n    tab.setTabGravity(TabLayout.GRAVITY_CENTER)\n    tab.setupWithViewPager(viewPager)\n    getData()\nend\n"
  },
  {
    "path": "lua_main/activity_plugins.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- Load plugin from api\n--\nrequire \"import\"\n\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaHttp\"\nimport \"android.os.Build\"\nimport \"androlua.LuaAdapter\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"androlua.widget.marqueetext.MarqueeTextView\"\n\nlocal FileUtils = import \"androlua.common.LuaFileUtils\"\nlocal JSON = require \"cjson\"\nlocal uihelper = require \"uihelper\"\n-- create view table\nlocal layout = {\n    LinearLayout,\n    orientation = \"vertical\",\n    layout_width = \"fill\",\n    statusBarColor = \"#222222\",\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#222222\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"56dp\",\n            layout_height = \"fill\",\n            src = \"@drawable/ic_menu_back\",\n            scaleType = \"centerInside\",\n            background = \"@drawable/layout_selector_tran\",\n        },\n        {\n            TextView,\n            id = \"tv_title\",\n            layout_height = \"fill\",\n            layout_marginLeft = \"72dp\",\n            gravity = \"center_vertical\",\n            textColor = \"#ffffff\",\n            textSize = \"18sp\",\n            text = \"插件列表\",\n        },\n        {\n            TextView,\n            layout_height = \"fill\",\n            paddingRight = \"16dp\",\n            paddingLeft = \"16dp\",\n            layout_gravity = \"right\",\n            id = \"tv_support\",\n            gravity = \"center\",\n            textColor = \"#ffffff\",\n            textSize = \"13sp\",\n            text = \"捐赠\",\n            background = \"@drawable/layout_selector_tran\",\n        },\n    },\n    {\n        ListView,\n        id = \"listview\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    }\n}\n\nlocal item_view = {\n    FrameLayout,\n    layout_width = \"fill\",\n    layout_height = \"80dp\",\n    padding = \"16dp\",\n    {\n        ImageView,\n        id = \"icon\",\n        layout_gravity = \"center_vertical\",\n        layout_width = \"48dp\",\n        layout_height = \"48dp\",\n        scaleType = \"centerInside\",\n    },\n    {\n        TextView,\n        id = \"text\",\n        layout_width = \"fill\",\n        layout_marginLeft = \"56dp\",\n        textSize = \"12sp\",\n        textColor = \"#222222\",\n        layout_gravity = \"top\",\n    },\n    {\n        TextView,\n        id = \"tv_version\",\n        layout_width = \"fill\",\n        layout_marginLeft = \"56dp\",\n        layout_marginRight = \"96dp\",\n        textSize = \"10sp\",\n        textColor = \"#666666\",\n        layout_gravity = \"center_vertical\",\n    },\n    {\n        MarqueeTextView,\n        id = \"desc\",\n        textSize = \"10sp\",\n        textColor = \"#666666\",\n        layout_width = \"fill\",\n        layout_marginLeft = \"56dp\",\n        layout_marginRight = \"96dp\",\n        layout_gravity = \"bottom\",\n    },\n    {\n        TextView,\n        layout_width = \"68dp\",\n        layout_height = \"32dp\",\n        background = \"#666666\",\n        layout_marginTop = \"8dp\",\n        gravity = \"center\",\n        id = \"download\",\n        text = \"下载\",\n        textSize = \"12sp\",\n        layout_gravity = \"right\",\n    },\n}\n\n\nlocal strokeWidth = 2;\nlocal roundRadius = 8;\nlocal strokeColor = 0xFF2E3135\n\nlocal gd = GradientDrawable()\ngd.setCornerRadius(roundRadius)\ngd.setStroke(strokeWidth, strokeColor)\n\nlocal function flatType(type)\n    if type == 'uninstall' then return '卸载'\n    elseif type == 'update' then return '更新'\n    elseif type == 'downloading' then return '下载中'\n    else return '安装'\n    end\nend\n\nlocal function flatTypeColor(type)\n    local color = 0xff111111\n    if type == 'uninstall' then color = 0xff888888\n    elseif type == 'update' then color = 0xff222222\n    elseif type == 'downloading' then color = 0xffc22525\n    end\n    return color\nend\n\nlocal data = {} -- plugin list\n\nlocal adapter\n\nlocal function notifyAdapterData()\n    uihelper.runOnUiThread(activity, function() adapter.notifyDataSetChanged() end)\nend\n\nlocal function compareWithLocal(localList, plugin)\n    plugin.type = 'install'\n    for i = 1, #localList do\n        local p = localList[i - 1]\n        if p.getId() == plugin.id then\n            if p.getVersionCode() < plugin.versionCode then\n                plugin.type = 'update'\n                plugin.versionName = string.format('%s -> %s', p.getVersionName(), plugin.versionName)\n                plugin.position = plugin.position - 999\n            else plugin.type = 'uninstall'\n            end\n        end\n    end\n    if plugin.type == 'install' then\n        plugin.position = -plugin.position\n    end\nend\n\n\n\nlocal function getData()\n    local options = {\n        url = 'https://coding.net/u/zhangyuhan/p/api_luanroid/git/raw/master/api/plugins'\n    }\n    LuaHttp.request(options, function(error, code, body)\n        local localList = FileUtils.getPluginList()\n        local json = JSON.decode(body)\n        local list = json.data\n        for i = 1, #list do\n            local plugin = list[i]\n            plugin.position = i\n            compareWithLocal(localList, plugin)\n            data[#data + 1] = plugin;\n        end\n        table.sort(data, function(l, r) return l.position < r.position end)\n        notifyAdapterData()\n    end)\nend\n\n\nlocal function downloadPlugin(plugin)\n    plugin.type = 'downloading'\n    notifyAdapterData()\n    FileUtils.downloadPlugin(plugin.download, plugin.id, function(pluginDir)\n        plugin.type = 'uninstall'\n        notifyAdapterData()\n    end)\nend\n\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    activity.disableDrawer()\n    back.onClick = function()\n        activity.finish()\n    end\n\n    tv_support.onClick = function()\n        xpcall(function()\n            local intentFullUrl = \"intent://platformapi/startapp?saId=10000007&clientVersion=3.7.0.0718&qrcode=https%3A%2F%2Fqr.alipay.com%2Faex09002nkvmcsullzrwg2b%3F_s%3Dweb-other&_t=1472443966571#Intent;scheme=alipayqr;package=com.eg.android.AlipayGphone;end\"\n            activity.startActivity(Intent.parseUri(intentFullUrl, 1));\n        end,\n            function()\n                local url = \"https://qr.alipay.com/aex09002nkvmcsullzrwg2b\";\n                activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)));\n            end)\n    end\n\n    adapter = LuaAdapter(luajava.createProxy(\"androlua.LuaAdapter$AdapterCreator\", {\n        getCount = function() return #data end,\n        getView = function(position, convertView, parent)\n            position = position + 1 -- lua 索引从 1开始\n\n            if convertView == nil then\n                local views = {} -- store views\n                convertView = loadlayout(item_view, views, ListView)\n                if Build.VERSION.SDK_INT < 16 then\n                    views.download.setBackgroundDrawable(gd);\n                else\n                    views.download.setBackground(gd);\n                end\n                convertView.getLayoutParams().width = parent.getWidth()\n                convertView.setTag(views)\n            end\n\n            local views = convertView.getTag()\n            local plugin = data[position]\n            if views == nil or plugin == nil then return end\n\n            LuaImageLoader.loadWithRadius(views.icon, 40, plugin.icon)\n            views.text.setText(plugin.name)\n            views.desc.setText(plugin.desc)\n            views.tv_version.setText(plugin.versionName)\n            views.download.setText(flatType(plugin.type))\n            views.download.setTextColor(flatTypeColor(plugin.type))\n            views.download.onClick = function(view)\n                if plugin.type == 'downloading' then\n                    return\n                elseif plugin.type == 'update' or plugin.type == 'install' then\n                    plugin.type = 'downloading'\n                    downloadPlugin(plugin)\n                else\n                    FileUtils.removePlugin(plugin.id)\n                    plugin.type = 'install'\n                    notifyAdapterData()\n                end\n            end\n            return convertView\n        end\n    }))\n\n    listview.setAdapter(adapter)\n    getData()\nend\n"
  },
  {
    "path": "lua_main/activity_setting.lua",
    "content": "require \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v7.widget.AppCompatCheckBox\"\nimport \"android.net.Uri\"\nimport \"java.io.File\"\nimport \"androlua.utils.DialogUtils\"\nimport \"android.support.v7.widget.AppCompatSeekBar\"\nimport \"androlua.common.LuaFileUtils\"\nimport \"android.graphics.BitmapFactory\"\nlocal Media = import \"android.provider.MediaStore$Images$Media\"\nlocal CompressFormat = import \"android.graphics.Bitmap$CompressFormat\"\n\nlocal DialogBuilder = import \"android.app.AlertDialog$Builder\"\n\nlocal JSON = require \"cjson\"\nlocal config_file = \"luandroid\"\nlocal sp = activity.getSharedPreferences(config_file, Context.MODE_PRIVATE)\nlocal CODE_PICK_BG, CODE_PICK_LOGO, CODE_PICK_SPLASH = 0x1, 0x2, 0x3\nlocal config = JSON.decode(sp.getString('config', '{}'))\n\nlocal divider = {\n    View,\n    layout_width = \"match\",\n    layout_height = \"0.5dp\",\n    background = \"#f1f1f1\",\n}\n\nlocal dialog_progress = {\n    RelativeLayout,\n    padding = \"16dp\",\n    {\n        TextView,\n        id = 'tv_progress',\n        layout_alignParentRight = true,\n        layout_centerVertical = true,\n        textSize = \"14sp\",\n        textColor = \"#444444\",\n    },\n    {\n        AppCompatSeekBar,\n        id = 'progress',\n        layout_width = \"fill\",\n        layout_toLeftOf = \"tv_progress\"\n    }\n}\n\nlocal function layoutTitle(text)\n    return {\n        TextView,\n        layout_width = \"fill\",\n        layout_height = \"16dp\",\n        textColor = \"#666666\",\n        background = \"#fafafa\",\n        textSize = \"13sp\",\n        gravity = \"center_vertical\",\n        paddingLeft = \"16dp\",\n    }\nend\n\nlocal function layoutText(text, id, tvId)\n    return {\n        LinearLayout,\n        id = id,\n        layout_height = \"48dp\",\n        layout_width = \"fill\",\n        orientation = \"horizontal\",\n        gravity = \"center_vertical\",\n        background = \"@drawable/layout_selector_tran\",\n        {\n            TextView,\n            paddingLeft = \"16dp\",\n            text = text,\n            textColor = \"#444444\",\n            textSize = \"14sp\",\n        },\n        {\n            TextView,\n            id = tvId,\n            singleLine = true,\n            ellipsize = \"middle\",\n            layout_width = \"fill\",\n            paddingLeft = \"16dp\",\n            paddingRight = \"16dp\",\n            gravity = 'right',\n            textColor = \"#999999\",\n            textSize = \"12sp\",\n        }\n    }\nend\n\nlocal function layoutCheckBox(text, id, checked)\n    return {\n        RelativeLayout,\n        layout_width = \"match\",\n        layout_height = \"48dp\",\n        paddingLeft = \"16dp\",\n        {\n            TextView,\n            text = text,\n            textColor = \"#444444\",\n            textSize = \"14sp\",\n            layout_centerVertical = true,\n        },\n        {\n            AppCompatCheckBox,\n            id = id,\n            layout_width = \"50dp\",\n            layout_height = \"50dp\",\n            layout_centerVertical = true,\n            layout_alignParentRight = true,\n            checked = checked,\n        }\n    }\nend\n\nlocal layout_content = {\n    ScrollView,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    background = \"#FFFFFF\",\n    {\n        LinearLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        orientation = \"vertical\",\n\n        layoutTitle('界面'),\n        layoutText('首页背景', 'layout_home_bg', 'tv_home_bg'),\n        divider,\n        layoutText('首页Logo', 'layout_home_logo', 'tv_home_logo'),\n        divider,\n        layoutText('APP启动图', 'layout_home_splash', 'tv_home_splash'),\n        divider,\n        layoutText('图标圆角大小', 'layout_home_radius', 'tv_home_radius'),\n        divider,\n        layoutText('背景不透明度', 'layout_home_alpha', 'tv_home_alpha'),\n        divider,\n        layoutText('恢复默认设置', 'layout_reset'),\n\n        layoutTitle('其他'),\n        {\n            LinearLayout,\n            id = 'layout_support',\n            layout_height = \"48dp\",\n            layout_width = \"fill\",\n            orientation = \"horizontal\",\n            gravity = \"center_vertical\",\n            background = \"@drawable/layout_selector_tran\",\n            {\n                TextView,\n                paddingLeft = \"16dp\",\n                text = '续一秒(๑￫ܫ￩)',\n                textColor = \"#D86758\",\n                textSize = \"14sp\",\n            },\n        },\n        divider,\n        layoutText('应用评分/更新', 'layout_market'),\n        divider,\n        layoutText('推荐给好基友', 'layout_shareapp'),\n\n        layoutTitle(''),\n    }\n}\n\nlocal layout = {\n    LinearLayout,\n    layout_width = \"match\",\n    layout_height = \"match\",\n    orientation = \"vertical\",\n    background = \"#666666\",\n    statusBarColor = \"#222222\",\n    {\n        LinearLayout,\n        orientation = \"horizontal\",\n        layout_width = \"fill\",\n        layout_height = \"56dp\",\n        background = \"#222222\",\n        gravity = \"center_vertical\",\n        {\n            ImageView,\n            id = \"back\",\n            layout_width = \"56dp\",\n            layout_height = \"56dp\",\n            src = \"@drawable/ic_menu_back\",\n            background = \"@drawable/layout_selector_tran\",\n            scaleType = \"centerInside\",\n        },\n        {\n            TextView,\n            layout_height = \"56dp\",\n            layout_width = \"fill\",\n            id = \"tv_title\",\n            gravity = \"center_vertical\",\n            paddingLeft = \"8dp\",\n            textColor = \"#FFFFFF\",\n            textSize = \"16sp\",\n            text = \"设置\",\n        },\n    },\n    {\n        FrameLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        layout_content,\n        {\n            View,\n            layout_width = \"fill\",\n            layout_height = \"3dp\",\n            background = \"@drawable/shadow_line_top\",\n        }\n    },\n}\n\nlocal function layout_item_pay(id, drawable, text)\n    return {\n        LinearLayout,\n        gravity = 'center_vertical',\n        background = '@drawable/layout_selector_tran',\n        paddingTop = '8dp',\n        paddingLeft = '8dp',\n        paddingBottom = '8dp',\n        id = id,\n        {\n            ImageView,\n            layout_width = '72dp',\n            layout_height = '72dp',\n            src = drawable,\n        },\n        {\n            TextView,\n            layout_width = '200dp',\n            textSize = '14sp',\n            paddingLeft = '8dp',\n            textColor = '#222222',\n            text = text,\n        },\n    }\nend\n\nlocal layout_pay = {\n    LinearLayout,\n    layout_width = 'fill',\n    background = '#ffffff',\n    orientation = 'vertical',\n    gravity = 'center',\n    layout_item_pay('iv_wechat', '@drawable/wechat', '微信捐赠（zyhan8866）'),\n    layout_item_pay('iv_alipay', '@drawable/alipay', '支付宝捐赠'),\n    layout_item_pay('iv_qq', '@drawable/qq', 'QQ捐赠（1161745215）'),\n}\n\nlocal function updateConfigUI(config)\n    if config == nil then return end\n    tv_home_bg.setText(config.home_bg or '默认')\n    tv_home_logo.setText(config.home_logo or '默认')\n    tv_home_splash.setText(config.home_splash or '自动(每日一张)')\n    tv_home_radius.setText(config.home_icon_radius or '40')\n    tv_home_alpha.setText(config.home_bg_alpha or '9')\nend\n\nlocal function saveConfig(config)\n    sp.edit().putString(\"config\", JSON.encode(config)).apply()\n    updateConfigUI(config)\nend\n\nlocal function getIdentifier(type, name) -- drawable  ic_back\n    return activity.getResources().getIdentifier(name, type, activity.getPackageName())\nend\n\nlocal function copyText(text)\n    local clipboard = activity.getSystemService(Context.CLIPBOARD_SERVICE)\n    local clip = ClipData.newPlainText(\"氢应用\", text)\n    clipboard.setPrimaryClip(clip)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setContentView(loadlayout(layout))\n    activity.disableDrawer()\n    updateConfigUI(config)\n    back.onClick = function()\n        activity.finish()\n    end\n\n    layout_market.onClick = function()\n        local intent = Intent(Intent.ACTION_VIEW)\n        intent.setData(Uri.parse('market://details?id=pub.hydrogen.android'))\n        activity.startActivity(intent)\n    end\n\n    layout_home_bg.onClick = function()\n        pcall(function()\n            activity.toast('长按可恢复默认')\n            local intent = Intent(Intent.ACTION_GET_CONTENT)\n            intent.setType(\"image/*\")\n            activity.startActivityForResult(intent, CODE_PICK_BG)\n        end)\n    end\n\n    layout_home_logo.onClick = function()\n        pcall(function()\n            activity.toast('长按可恢复默认')\n            local intent = Intent(Intent.ACTION_GET_CONTENT)\n            intent.setType(\"image/*\")\n            activity.startActivityForResult(intent, CODE_PICK_LOGO)\n        end)\n    end\n\n    layout_home_splash.onClick = function()\n        pcall(function()\n            activity.toast('长按可恢复默认')\n            local intent = Intent(Intent.ACTION_GET_CONTENT)\n            intent.setType(\"image/*\")\n            activity.startActivityForResult(intent, CODE_PICK_SPLASH)\n        end)\n    end\n\n    layout_home_logo.setOnLongClickListener(luajava.createProxy('android.view.View$OnLongClickListener', {\n        onLongClick = function(view)\n            config.home_logo = nil\n            saveConfig(config)\n            activity.toast('已恢复默认')\n            return true\n        end\n    }))\n\n    layout_home_bg.setOnLongClickListener(luajava.createProxy('android.view.View$OnLongClickListener', {\n        onLongClick = function(view)\n            config.home_bg = nil\n            config.home_bg_alpha = '9'\n            saveConfig(config)\n            activity.toast('已恢复默认')\n            return true\n        end\n    }))\n\n    layout_home_splash.setOnLongClickListener(luajava.createProxy('android.view.View$OnLongClickListener', {\n        onLongClick = function(view)\n            config.home_splash = nil\n            saveConfig(config)\n            activity.toast('已恢复默认')\n            return true\n        end\n    }))\n\n    layout_home_radius.onClick = function()\n        local ids = {}\n        DialogBuilder(activity).setView(loadlayout(dialog_progress, ids, ViewGroup)).show()\n        ids.progress.setMax(50)\n        ids.progress.setProgress(tonumber(config.home_icon_radius) or 40)\n        ids.tv_progress.setText(config.home_icon_radius or '40')\n        ids.progress.setOnSeekBarChangeListener(luajava.createProxy('android.widget.SeekBar$OnSeekBarChangeListener', {\n            onProgressChanged = function(bar, progress, fromUser)\n                config.home_icon_radius = '' .. progress\n                ids.tv_progress.setText(config.home_icon_radius)\n                saveConfig(config)\n            end\n        }))\n    end\n\n    layout_home_alpha.onClick = function()\n        local ids = {}\n        DialogBuilder(activity).setView(loadlayout(dialog_progress, ids, ViewGroup)).show()\n        ids.progress.setMax(10)\n        ids.progress.setProgress(tonumber(config.home_bg_alpha) or 9)\n        ids.tv_progress.setText(config.home_bg_alpha or '9')\n        ids.progress.setOnSeekBarChangeListener(luajava.createProxy('android.widget.SeekBar$OnSeekBarChangeListener', {\n            onProgressChanged = function(bar, progress, fromUser)\n                config.home_bg_alpha = '' .. progress\n                ids.tv_progress.setText(config.home_bg_alpha)\n                saveConfig(config)\n            end\n        }))\n    end\n\n    layout_reset.onClick = function()\n        DialogBuilder(activity).setTitle('重置设置').setMessage('重置到默认的设置？').setNegativeButton('取消', nil).setPositiveButton('确定', luajava.createProxy('android.content.DialogInterface$OnClickListener', {\n            onClick = function(dialog, which)\n                config = {}\n                saveConfig(config)\n            end\n        })).show()\n    end\n\n    layout_shareapp.onClick = function()\n        pcall(function()\n            local intent = Intent(Intent.ACTION_SEND)\n            intent.putExtra(Intent.EXTRA_TEXT, '震惊，所有用了这个 APP 的人都再也离不开了! http://coolapk.com/apk/pub.hydrogen.android');\n            intent.setType(\"text/plain\");\n            activity.startActivity(Intent.createChooser(intent, '分享'))\n        end)\n    end\n\n    layout_support.onClick = function()\n        local ids = {}\n        DialogBuilder(activity).setView(loadlayout(layout_pay, ids, ViewGroup)).show()\n        ids.iv_wechat.onClick = function()\n            copyText('zyhan8866')\n            activity.toast('已复制\"zyhan8866\"')\n\n            local bitmap = BitmapFactory.decodeResource(activity.getResources(), getIdentifier('drawable', 'qr_wechat'));\n            local path = activity.getExternalFilesDir('qr').getAbsolutePath() .. '/qr_wechat.png'\n            LuaFileUtils.bitmapToFile(bitmap, File(path), CompressFormat.PNG, 100)\n            Media.insertImage(activity.getContentResolver(), path, \"氢应用\", \"微信二维码\");\n            activity.toast('二维码已保存：' .. path)\n\n            pcall(function()\n                local intent = Intent(Intent.ACTION_MAIN)\n                local cmp = ComponentName(\"com.tencent.mm\", \"com.tencent.mm.ui.LauncherUI\")\n                intent.addCategory(Intent.CATEGORY_LAUNCHER);\n                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                intent.setComponent(cmp);\n                activity.startActivity(intent)\n            end)\n        end\n        ids.iv_alipay.onClick = function()\n            xpcall(function()\n                local intentFullUrl = \"intent://platformapi/startapp?saId=10000007&clientVersion=3.7.0.0718&qrcode=https%3A%2F%2Fqr.alipay.com%2Ftsx04452i1hjmquygc9be4b%3F_s%3Dweb-other&_t=1472443966571#Intent;scheme=alipayqr;package=com.eg.android.AlipayGphone;end\"\n                activity.startActivity(Intent.parseUri(intentFullUrl, 1))\n            end,\n                function()\n                    local url = \"https://qr.alipay.com/tsx04452i1hjmquygc9be4b\"\n                    activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))\n                end)\n        end\n        ids.iv_qq.onClick = function()\n            local qqUrl = \"mqqwpa://im/chat?chat_type=wpa&uin=1161745215&version=1\"\n            activity.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(qqUrl)))\n        end\n    end\nend\n\nfunction onActivityResult(requestCode, resultCode, data)\n    if resultCode ~= -1 or data == nil then\n        return\n    end\n    local uri = data.getData()\n    if requestCode == CODE_PICK_BG and uri then\n        config.home_bg = uri.toString()\n        saveConfig(config)\n        return\n    end\n\n    if requestCode == CODE_PICK_LOGO and uri then\n        config.home_logo = uri.toString()\n        saveConfig(config)\n        return\n    end\n\n    if requestCode == CODE_PICK_SPLASH and uri then\n        config.home_splash = uri.toString()\n        saveConfig(config)\n        return\n    end\nend\n"
  },
  {
    "path": "lua_main/filehelper.lua",
    "content": "local filehelper = {}\n\n--\nlocal function readfile(path)\n    local file = io.open(path, \"rb\") -- r read mode and b binary mode\n    if not file then return nil end\n    local content = file:read \"*a\" -- *a or *all reads the whole file\n    file:close()\n    return content\nend\n\n--------------------------------------------\n-- 功能：写入文件\n-- 输入：文件名, 内容\n-- 输出：生成的文件里面包含内容\nlocal function writefile(path, content)\n    print('writefile:' .. path, content)\n    local wfile = io.open(path, \"w\") --写入文件(w覆盖)\n    assert(wfile) --打开时验证是否出错\n    wfile:write(content) --写入传入的内容\n    wfile:close() --调用结束后记得关闭\nend\n\nfilehelper.readfile = readfile\nfilehelper.writefile = writefile\nreturn filehelper\n"
  },
  {
    "path": "lua_main/fragment_home.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nlocal FileUtils = import \"androlua.common.LuaFileUtils\"\nlocal DialogBuilder = import \"android.app.AlertDialog$Builder\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.os.Build\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"androlua.LuaActivity\"\nimport \"androlua.LuaAdapter\"\nimport \"android.support.v7.widget.GridLayoutManager\"\nimport \"android.support.v7.widget.helper.ItemTouchHelper\"\nimport \"pub.hanks.sample.adapter.DragTouchHelper\"\nimport \"android.support.design.widget.BottomSheetBehavior\"\nimport \"android.support.design.widget.CoordinatorLayout\"\nimport \"android.support.v4.view.MotionEventCompat\"\nimport \"android.view.MotionEvent\"\nlocal Orientation = import \"android.graphics.drawable.GradientDrawable$Orientation\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal log = require \"log\"\n\nlocal function newInstance()\n    -- create view table\n    local layout = {\n        CoordinatorLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        focusable = true,\n        focusableInTouchMode = true,\n        {\n            LinearLayout,\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n            gravity = \"center_horizontal\",\n            orientation = 1,\n            paddingLeft = \"16dp\",\n            paddingRight = \"16dp\",\n            {\n                RelativeLayout,\n                layout_height = \"48dp\",\n                layout_width = \"fill\",\n                layout_marginLeft = \"16dp\",\n                layout_marginTop = \"36dp\",\n                layout_marginRight = \"8dp\",\n                {\n                    TextView,\n                    id = \"tv_date\",\n                    text = \"23月33日 333\",\n                    textSize = \"14sp\",\n                    layout_centerVertical = true,\n                    textColor = \"#aa333333\",\n                },\n                {\n                    ImageView,\n                    id = \"iv_setting\",\n                    layout_height = \"48dp\",\n                    layout_width = \"48dp\",\n                    padding = \"12dp\",\n                    scaleType = \"center\",\n                    src = \"@drawable/ic_setting\",\n                    layout_alignParentRight = true,\n                }\n            },\n            {\n                ImageView,\n                id = \"iv_logo\",\n                layout_height = \"56dp\",\n                layout_width = \"56dp\",\n                layout_marginTop = \"24dp\",\n                visibility = \"invisible\",\n                src = \"@drawable/logo_no_bg\",\n            },\n            {\n                RelativeLayout,\n                layout_height = \"48dp\",\n                layout_width = \"fill\",\n                background = \"#AAEBF0F2\",\n                layout_marginLeft = \"16dp\",\n                layout_marginTop = \"36dp\",\n                layout_marginRight = \"16dp\",\n                {\n                    TextView,\n                    id = \"tv_add_plugin\",\n                    layout_height = \"fill\",\n                    layout_width = \"fill\",\n                    gravity = \"center\",\n                    text = \"漫画 | 资讯 | 视频 | 图片\",\n                    textColor = \"#9DAEBF\",\n                    textSize = \"12sp\",\n                },\n                {\n                    TextView,\n                    id = \"tv_updateCount\",\n                    layout_height = \"18dp\",\n                    layout_width = \"18dp\",\n                    layout_margin = \"12dp\",\n                    layout_alignParentRight = true,\n                    layout_centerVertical = true,\n                    gravity = \"center\",\n                    text = \"3\",\n                    textColor = \"#9DAEBF\",\n                    textSize = \"9sp\",\n                    elevation = \"1dp\",\n                    visibility = 8,\n                },\n            },\n            {\n                RecyclerView,\n                id = \"recyclerView\",\n                layout_width = \"fill\",\n                layout_marginTop = \"32dp\",\n                clipToPadding = false,\n                layout_marginLeft = \"8dp\",\n                layout_marginRight = \"8dp\",\n                overScrollMode = 2,\n                fadingEdgeLength = 0,\n                verticalFadingEdgeEnabled = false,\n                horizontalFadingEdgeEnabled = false,\n            },\n        },\n    }\n    local sp = activity.getSharedPreferences(\"luandroid\", Context.MODE_PRIVATE)\n    local item_view = {\n        RelativeLayout,\n        layout_height = \"70dp\",\n        background = \"@drawable/layout_selector_tran\",\n        {\n            ImageView,\n            id = \"icon\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginTop = \"6dp\",\n            layout_centerHorizontal = true,\n        },\n        {\n            TextView,\n            id = \"text\",\n            layout_below = \"icon\",\n            textColor = \"#444444\",\n            textSize = \"9sp\",\n            gravity = \"center\",\n            layout_width = \"fill\",\n            layout_height = \"22dp\",\n        },\n        {\n            ImageView,\n            layout_alignParentRight = true,\n            id = \"ic_del\",\n            layout_marginRight = \"2dp\",\n            layout_width = \"24dp\",\n            layout_height = \"24dp\",\n            src = \"@drawable/ic_clear\",\n            visibility = 'gone',\n        },\n    }\n    local hadLoadData\n    local isVisible\n    local lastId\n    local params = { rid = rid }\n    local data = {}\n    local ids = {}\n    local config = {}\n    local isDragging = false\n    local weeks = { \"星期日\", \"星期一\", \"星期二\", \"星期三\", \"星期四\", \"星期五\", \"星期六\" }\n    local adapter\n    local touchHelper\n    local gd = GradientDrawable()\n    gd.setShape(GradientDrawable.OVAL)\n    gd.setColor(0xFFFFFFFF)\n    local function isDraggingIcons()\n        return isDragging\n    end\n\n    local function setDraggingIcons(drag)\n        isDragging = drag\n    end\n\n    local function newActivity(luaPath)\n        local intent = Intent(activity, LuaActivity)\n        intent.putExtra(\"luaPath\", luaPath)\n        activity.startActivity(intent)\n    end\n\n    local function launchPluginManager()\n        newActivity(luajava.luadir .. '/activity_plugins.lua')\n    end\n\n    local function saveConfig(config)\n        sp.edit().putString(\"config\", JSON.encode(config)).apply()\n    end\n\n    local function needUpdate(localList, plugin)\n        for i = 1, #localList do\n            local p = localList[i - 1]\n            if p.getId() == plugin.id and p.getVersionCode() < plugin.versionCode then\n                return true\n            end\n        end\n        return false\n    end\n\n    local function checkPluginUpdate()\n        if config.update_inwifi == false then return end\n        local url = 'https://coding.net/u/zhangyuhan/p/api_luanroid/git/raw/master/api/plugins'\n        LuaHttp.request({ url = url }, function(error, code, body)\n            local localList = FileUtils.getPluginList()\n            local json = JSON.decode(body)\n            local list = json.data\n            local count = 0\n            for i = 1, #list do\n                local plugin = list[i]\n                if needUpdate(localList, plugin) then\n                    count = count + 1\n                end\n            end\n            uihelper.runOnUiThread(activity, function()\n                if count > 0 then\n                    ids.tv_updateCount.setVisibility(0)\n                    if Build.VERSION.SDK_INT < 16 then\n                        ids.tv_updateCount.setBackgroundDrawable(gd);\n                    else\n                        ids.tv_updateCount.setBackground(gd);\n                    end\n                    ids.tv_updateCount.setText(string.format('%d', count))\n                else\n                    ids.tv_updateCount.setVisibility(8)\n                end\n            end)\n        end)\n    end\n\n    local function getAdapter(mData, changeColor, getItemCountFunc, getTouchHelperFunc)\n        return LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n            getItemCount = getItemCountFunc,\n            getItemViewType = function(position) return 0 end,\n            onCreateViewHolder = function(parent, viewType)\n                local views = {}\n                local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n                holder.itemView.setTag(views)\n                holder.itemView.getLayoutParams().width = ids.recyclerView.getWidth() / 5 - 1\n                holder.itemView.setOnTouchListener(luajava.createProxy('android.view.View$OnTouchListener', {\n                    onTouch = function(v, event)\n                        if isDragging and MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN then\n                            getTouchHelperFunc().startDrag(holder)\n                        end\n                        return false\n                    end\n                }))\n                holder.itemView.setOnLongClickListener(luajava.createProxy('android.view.View$OnLongClickListener', {\n                    onLongClick = function(v)\n                        isDragging = true\n                        adapter.notifyDataSetChanged()\n                        return true\n                    end\n                }))\n                holder.itemView.onClick = function()\n                    local p = holder.getAdapterPosition() + 1\n                    local item = mData[p]\n                    newActivity(item.launchPage)\n                end\n                views.ic_del.onClick = function()\n                    local p = holder.getAdapterPosition()\n                    local id\n                    if p + 1 <= #data then\n                        id = data[p + 1].id\n                        table.remove(data, p + 1)\n                        adapter.notifyItemRemoved(p)\n                    end\n                    if id then FileUtils.removePlugin(id) end\n                end\n                return holder\n            end,\n            onBindViewHolder = function(holder, position)\n                position = position + 1\n                local views = holder.itemView.getTag()\n                local item = mData[position]\n                if views == nil or item == nil then return end\n                if isDragging then\n                    views.ic_del.setScaleX(0)\n                    views.ic_del.setScaleY(0)\n                    views.ic_del.setVisibility(0)\n                    views.ic_del.animate().scaleX(1).scaleY(1).start()\n                else\n                    views.ic_del.setVisibility(8)\n                end\n\n                local icon = item.icon\n                local radius = tonumber(config.home_icon_radius or '40')\n                LuaImageLoader.loadWithRadius(views.icon, radius, icon)\n                views.text.setText(item.text)\n                local alpha = tonumber(config.home_bg_alpha or 9)\n                if changeColor and alpha <= 5 then\n                    views.text.setTextColor(0xFFFFFFFF)\n                else\n                    views.text.setTextColor(0xFF444444)\n                end\n            end,\n        }))\n    end\n\n\n    local function getTouchHelperCallback(mData, mAdapter)\n        return DragTouchHelper(luajava.createProxy('pub.hanks.sample.adapter.DragTouchHelper$Creator', {\n            onMove = function(rec, holder, target)\n                local fromPosition = holder.getAdapterPosition() + 1\n                local toPosition = target.getAdapterPosition() + 1\n                local tmp = mData[fromPosition]\n                table.remove(mData, fromPosition)\n                table.insert(mData, toPosition, tmp)\n                mAdapter.notifyItemMoved(fromPosition - 1, toPosition - 1)\n            end,\n            isLongPressDragEnabled = function() return false end,\n            clearView = function(rec, holder)\n                local sortApps = {}\n                for i = 1, #mData do\n                    sortApps[#sortApps + 1] = mData[i].id\n                end\n                config.sortApps = sortApps\n                saveConfig(config)\n            end,\n            getDragFlags = function() return 0xF end,\n            getSwipeFlags = function() return 0 end,\n        }))\n    end\n\n\n    local function getData()\n        for k, v in pairs(data) do\n            data[k] = nil\n        end\n        config = JSON.decode(sp.getString('config', '{}'))\n        local sortApps = config.sortApps or {}\n        local localList = LuaFileUtils.getPluginList()\n        for i = 1, #localList do\n            local p = localList[i - 1]\n            local item = {\n                id = p.getId(),\n                text = p.getName(),\n                launchPage = p.getMainPath(),\n                icon = p.getIconPath(),\n                position = 9999 + i,\n            }\n            data[#data + 1] = item\n            for j = 1, #sortApps do\n                if sortApps[j] == item.id then\n                    item.position = j\n                end\n            end\n        end\n        -- sort\n        table.sort(data, function(l, r) return l.position < r.position end)\n        adapter.notifyDataSetChanged()\n\n        -- save new config\n        local newSortApps = {}\n        for i = 1, #data do\n            newSortApps[#newSortApps + 1] = data[i].id\n        end\n        config.sortApps = newSortApps\n        saveConfig(config)\n    end\n\n    -- 获取类似 @drawable/ic_back 的资源\n    local function getIdentifier(type, name) -- drawable  ic_back\n        return activity.getResources().getIdentifier(name, type, activity.getPackageName())\n    end\n\n    adapter = getAdapter(data, true, function()\n        local size = #data\n        if size > 20 then size = 20 end\n        return size\n    end, function() return touchHelper end)\n\n    local fragment = LuaFragment.newInstance()\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onResume = function()\n            getData()\n            -- logo\n            if config.home_logo and config.home_logo ~= '' then\n                LuaImageLoader.loadWithRadius(ids.iv_logo, 36, config.home_logo)\n            else\n                ids.iv_logo.setImageResource(getIdentifier('drawable', 'logo_no_bg'))\n            end\n            checkPluginUpdate()\n        end,\n        onViewCreated = function(view, savedInstanceState)\n\n            ids.recyclerView.setLayoutManager(GridLayoutManager(activity, 5))\n            ids.recyclerView.setAdapter(adapter)\n            touchHelper = ItemTouchHelper(getTouchHelperCallback(data, adapter))\n            touchHelper.attachToRecyclerView(ids.recyclerView)\n\n            ids.tv_date.setText(os.date('%m月%d日 ') .. weeks[os.date('%w') + 1])\n            ids.iv_logo.onClick = function(view)\n                newActivity(luajava.luadir .. '/activity_setting.lua')\n            end\n            ids.iv_setting.onClick = function(view)\n                newActivity(luajava.luadir .. '/activity_setting.lua')\n            end\n            ids.tv_add_plugin.onClick = function(args)\n                launchPluginManager()\n            end\n        end,\n    }))\n    return fragment, adapter, getData, isDraggingIcons, setDraggingIcons\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua_main/fragment_list.lua",
    "content": "--\n-- Created by IntelliJ IDEA.\n-- User: hanks\n-- Date: 2017/5/13\n-- Time: 00:01\n-- To change this template use File | Settings | File Templates.\n--\nrequire \"import\"\n\nlocal FileUtils = import \"androlua.common.LuaFileUtils\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.LuaFragment\"\nimport \"androlua.LuaHttp\"\nimport \"androlua.widget.webview.WebViewActivity\"\nimport \"android.support.v4.widget.SwipeRefreshLayout\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.os.Build\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"androlua.LuaActivity\"\nimport \"androlua.LuaAdapter\"\nimport \"android.support.v7.widget.GridLayoutManager\"\nimport \"android.support.v7.widget.helper.ItemTouchHelper\"\nimport \"pub.hanks.sample.adapter.DragTouchHelper\"\nimport \"android.support.design.widget.BottomSheetBehavior\"\nimport \"android.support.design.widget.CoordinatorLayout\"\nimport \"android.support.v4.view.MotionEventCompat\"\nimport \"android.view.MotionEvent\"\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\n\nlocal function newInstance()\n    -- create view table\n    local layout = {\n        CoordinatorLayout,\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        focusable = true,\n        focusableInTouchMode = true,\n        {\n            LinearLayout,\n            layout_width = \"fill\",\n            layout_height = \"fill\",\n            gravity = \"center_horizontal\",\n            orientation = 1,\n            paddingLeft = \"16dp\",\n            paddingRight = \"16dp\",\n            {\n                RelativeLayout,\n                layout_height = \"48dp\",\n                layout_width = \"fill\",\n                layout_marginLeft = \"16dp\",\n                layout_marginTop = \"36dp\",\n                layout_marginRight = \"8dp\",\n                {\n                    TextView,\n                    id = \"tv_date\",\n                    text = \"23月33日 333\",\n                    textSize = \"14sp\",\n                    layout_centerVertical = true,\n                    textColor = \"#aa333333\",\n                },\n                {\n                    ImageView,\n                    id = \"iv_setting\",\n                    layout_height = \"48dp\",\n                    layout_width = \"48dp\",\n                    padding = \"12dp\",\n                    scaleType = \"center\",\n                    src = \"@drawable/ic_setting\",\n                    layout_alignParentRight = true,\n                }\n            },\n            {\n                RecyclerView,\n                id = \"recyclerView\",\n                layout_width = \"fill\",\n                layout_marginTop = \"16dp\",\n                layout_marginLeft = \"8dp\",\n                layout_marginRight = \"8dp\",\n                overScrollMode = 2,\n                fadingEdgeLength = 0,\n                verticalFadingEdgeEnabled = false,\n                horizontalFadingEdgeEnabled = false,\n            },\n        },\n    }\n    local sp = activity.getSharedPreferences(\"luandroid\", Context.MODE_PRIVATE)\n    local item_view = {\n        RelativeLayout,\n        layout_height = \"70dp\",\n        background = \"@drawable/layout_selector_tran\",\n        {\n            ImageView,\n            id = \"icon\",\n            layout_width = \"40dp\",\n            layout_height = \"40dp\",\n            layout_marginTop = \"6dp\",\n            layout_centerHorizontal = true,\n        },\n        {\n            TextView,\n            id = \"text\",\n            layout_below = \"icon\",\n            textColor = \"#444444\",\n            textSize = \"9sp\",\n            gravity = \"center\",\n            layout_width = \"fill\",\n            layout_height = \"22dp\",\n        },\n        {\n            ImageView,\n            layout_alignParentRight = true,\n            id = \"ic_del\",\n            layout_marginRight = \"2dp\",\n            layout_width = \"24dp\",\n            layout_height = \"24dp\",\n            src = \"@drawable/ic_clear\",\n            visibility = 'gone',\n        },\n    }\n    local hadLoadData\n    local isVisible\n    local lastId\n    local data = {}\n    local ids = {}\n    local config = {}\n    local isDragging = false\n    local weeks = { \"星期日\", \"星期一\", \"星期二\", \"星期三\", \"星期四\", \"星期五\", \"星期六\" }\n    local adapter\n    local touchHelper\n    local gd = GradientDrawable()\n    gd.setShape(GradientDrawable.OVAL)\n    gd.setColor(0xFFFFFFFF)\n\n    local function newActivity(luaPath)\n        local intent = Intent(activity, LuaActivity)\n        intent.putExtra(\"luaPath\", luaPath)\n        activity.startActivity(intent)\n    end\n\n    local function saveConfig(config)\n        sp.edit().putString(\"config\", JSON.encode(config)).apply()\n    end\n\n    local function getAdapter(mData, changeColor, getItemCountFunc, getTouchHelperFunc)\n        return LuaRecyclerAdapter(luajava.createProxy('androlua.adapter.LuaRecyclerAdapter$AdapterCreator', {\n            getItemCount = getItemCountFunc,\n            getItemViewType = function(position) return 0 end,\n            onCreateViewHolder = function(parent, viewType)\n                local views = {}\n                local holder = LuaRecyclerHolder(loadlayout(item_view, views, RecyclerView))\n                holder.itemView.setTag(views)\n                holder.itemView.getLayoutParams().width = ids.recyclerView.getWidth() / 5 - 1\n                holder.itemView.setOnTouchListener(luajava.createProxy('android.view.View$OnTouchListener', {\n                    onTouch = function(v, event)\n                        if isDragging and MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN then\n                            getTouchHelperFunc().startDrag(holder)\n                        end\n                        return false\n                    end\n                }))\n                holder.itemView.setOnLongClickListener(luajava.createProxy('android.view.View$OnLongClickListener', {\n                    onLongClick = function(v)\n                        isDragging = true\n                        adapter.notifyDataSetChanged()\n                        return true\n                    end\n                }))\n                holder.itemView.onClick = function()\n                    local p = holder.getAdapterPosition() + 1\n                    local item = mData[p]\n                    newActivity(item.launchPage)\n                end\n                views.ic_del.onClick = function()\n                    local p = holder.getAdapterPosition()\n                    local id\n                    if p + 1 <= #data then\n                        id = data[p + 1].id\n                        table.remove(data, p + 1)\n                        adapter.notifyItemRemoved(p)\n                    end\n                    if id then FileUtils.removePlugin(id) end\n                end\n                return holder\n            end,\n            onBindViewHolder = function(holder, position)\n                position = position + 1\n                local views = holder.itemView.getTag()\n                local item = mData[position]\n                if views == nil or item == nil then return end\n                if isDragging then\n                    views.ic_del.setScaleX(0)\n                    views.ic_del.setScaleY(0)\n                    views.ic_del.setVisibility(0)\n                    views.ic_del.animate().scaleX(1).scaleY(1).start()\n                else\n                    views.ic_del.setVisibility(8)\n                end\n\n                local icon = item.icon\n                local radius = tonumber(config.home_icon_radius or '40')\n                LuaImageLoader.loadWithRadius(views.icon, radius, icon)\n                views.text.setText(item.text)\n                local alpha = tonumber(config.home_bg_alpha or 9)\n                if changeColor and alpha <= 5 then\n                    views.text.setTextColor(0xFFFFFFFF)\n                else\n                    views.text.setTextColor(0xFF444444)\n                end\n            end,\n        }))\n    end\n\n    local function getTouchHelperCallback(mData, mAdapter)\n        return DragTouchHelper(luajava.createProxy('pub.hanks.sample.adapter.DragTouchHelper$Creator', {\n            onMove = function(rec, holder, target)\n                local fromPosition = holder.getAdapterPosition() + 1\n                local toPosition = target.getAdapterPosition() + 1\n                local tmp = mData[fromPosition]\n                table.remove(mData, fromPosition)\n                table.insert(mData, toPosition, tmp)\n                mAdapter.notifyItemMoved(fromPosition - 1, toPosition - 1)\n            end,\n            isLongPressDragEnabled = function() return false end,\n            clearView = function(rec, holder)\n                local sortApps = {}\n                for i = 1, #mData do\n                    sortApps[#sortApps + 1] = mData[i].id\n                end\n                config.sortApps = sortApps\n                saveConfig(config)\n            end,\n            getDragFlags = function() return 0xF end,\n            getSwipeFlags = function() return 0 end,\n        }))\n    end\n\n    local function getData()\n        for k, v in pairs(data) do\n            data[k] = nil\n        end\n        config = JSON.decode(sp.getString('config', '{}'))\n        local sortApps = config.sortApps or {}\n        local localList = LuaFileUtils.getPluginList()\n        for i = 1, #localList do\n            local p = localList[i - 1]\n            local item = {\n                id = p.getId(),\n                text = p.getName(),\n                launchPage = p.getMainPath(),\n                icon = p.getIconPath(),\n                position = 9999 + i,\n            }\n            data[#data + 1] = item\n            for j = 1, #sortApps do\n                if sortApps[j] == item.id then\n                    item.position = j\n                end\n            end\n        end\n        -- sort\n        table.sort(data, function(l, r) return l.position < r.position end)\n        adapter.notifyDataSetChanged()\n\n        -- save new config\n        local newSortApps = {}\n        for i = 1, #data do\n            newSortApps[#newSortApps + 1] = data[i].id\n        end\n        config.sortApps = newSortApps\n        saveConfig(config)\n    end\n\n    local function isDraggingIcons()\n        return isDragging\n    end\n\n    local function setDraggingIcons(drag)\n        isDragging = drag\n    end\n\n    adapter = getAdapter(data, true, function() return #data end, function() return touchHelper end)\n    local fragment = LuaFragment.newInstance()\n    fragment.setCreator(luajava.createProxy('androlua.LuaFragment$FragmentCreator', {\n        onCreateView = function(inflater, container, savedInstanceState)\n            return loadlayout(layout, ids)\n        end,\n        onViewCreated = function(view, savedInstanceState)\n            ids.recyclerView.setLayoutManager(GridLayoutManager(activity, 5))\n            ids.recyclerView.setAdapter(adapter)\n            touchHelper = ItemTouchHelper(getTouchHelperCallback(data, adapter))\n            touchHelper.attachToRecyclerView(ids.recyclerView)\n\n            ids.tv_date.setText(os.date('%m月%d日 ') .. weeks[os.date('%w') + 1])\n            ids.iv_setting.onClick = function(view)\n                newActivity(luajava.luadir .. '/activity_setting.lua')\n            end\n\n            getData()\n        end,\n    }))\n    return fragment, adapter, getData, isDraggingIcons, setDraggingIcons\nend\n\nreturn {\n    newInstance = newInstance\n}\n"
  },
  {
    "path": "lua_main/import.lua",
    "content": "local context = activity or service\nlocal require = require\nlocal table = require \"table\"\nlocal packages = {}\nlocal loaded = {} -- store bindclass\nlocal imported = {} -- store class via import function\nluajava.package = packages\nluajava.loaded = loaded\nluajava.imported = imported\nlocal _G = _G\nlocal insert = table.insert\nlocal new = luajava.new\nlocal bindClass = luajava.bindClass\nlocal dexes = luajava.astable(context.getClassLoaders())\nlocal libs = context.getLibrarys()\nlocal loaders = {} -- store fun ction to load class\n\nlocal function libsloader(path)\n    local p = libs[path:match(\"^%a+\")]\n    if p then\n        return assert(package.loadlib(p, \"luaopen_\" .. (path:gsub(\"%.\", \"_\")))), p\n    else\n        return \"\\n\\tno file ./libs/lib\" .. path .. \".so\"\n    end\nend\n\ntable.insert(package.searchers, libsloader)\n\n\n-- classname replace '_' to '&'\nlocal function massage_classname(classname)\n    if classname:find('_') then\n        classname = classname:gsub('_', '$')\n    end\n    return classname\nend\n\nlocal function import_class(classname, packagename)\n    packagename = massage_classname(packagename)\n    local res, class = pcall(bindClass, packagename)\n    if res then\n        loaded[classname] = class\n        return class\n    end\nend\n\nlocal function import_dex_class(classname, packagename)\n    packagename = massage_classname(packagename)\n    for _, dex in ipairs(dexes) do\n        local res, class = pcall(dex.loadClass, packagename)\n        if res then\n            loaded[classname] = class\n            return class\n        end\n    end\nend\n\nlocal pkgMT = {\n    __index = function(T, classname)\n        local ret, class = pcall(bindClass, rawget(T, \"__name\") .. classname)\n        if ret then\n            rawset(T, classname, class)\n            return class\n        else\n            error(classname .. \" is not in \" .. rawget(T, \"__name\"), 2)\n        end\n    end\n}\n\nlocal function import_pacckage(packagename)\n    local pkg = { __name = packagename }\n    setmetatable(pkg, pkgMT)\n    return pkg\nend\n\nlocal function import_1(classname)\n    for i, p in ipairs(packages) do\n        local class = import_class(classname, p .. classname)\n        if class then\n            return class\n        end\n    end\nend\n\nlocal function import_2(classname)\n    for _, p in ipairs(packages) do\n        local class = import_dex_class(classname, p .. classname)\n        if class then\n            return class\n        end\n    end\nend\n\nlocal function import_require(name)\n    local s, r = pcall(require, name)\n    if not s and not r:find(\"no file\") then\n        error(r, 0)\n    end\n    return s and r\nend\n\n-- append v to t\nlocal function append(t, v)\n    for _, _v in ipairs(t) do\n        if _v == v then\n            return\n        end\n    end\n    insert(t, v)\nend\n\nappend(loaders, import_1)\nappend(loaders, import_2)\n\nlocal globalMT = {\n    __index = function(T, classname)\n        for i, p in ipairs(loaders) do\n            local class = loaded[classname] or p(classname)\n            if class then\n                T[classname] = class\n                return class\n            end\n        end\n        return nil\n    end\n}\n--setmetatable(_G, globalMT)\n\n-- the implements of import fuction\nlocal function env_import(env)\n    local _env = env\n    setmetatable(_env, globalMT)\n    return function(package)\n        local j = package:find(':')\n        if j then\n            local dexname = package:sub(1, j - 1)\n            local classname = package:sub(j + 1, -1)\n            local class = context.loadDex(dexname).loadClass(classname)\n            local classname = package:match('([^%.$]+)$')\n            _env[classname] = class\n            append(imported, package)\n            return class\n        end\n        local i = package:find('%*$') -- android.widget.*\n        if i then -- a wildcard; put into the package list, including the final '.'\n            append(packages, package:sub(1, -2))\n            append(imported, package)\n            return import_pacckage(package:sub(1, -2))\n        else -- android.widget.Button\n            local classname = package:match('([^%.$]+)$')\n            local class = import_require(package) or import_class(classname, package) or import_dex_class(classname, package)\n            if class then\n                if class ~= true then\n                    --findtable(package)=class\n                    if type(class) ~= \"table\" then\n                        append(imported, package)\n                    end\n                    _env[classname] = class\n                end\n                return class\n            else\n                error(\"cannot find \" .. package, 2)\n            end\n        end\n    end\nend\n\nfunction compile(name)\n    append(dexes, context.loadDex(name))\nend\n\nimport = env_import(_G)\nappend(packages, '')\n\nimport 'java.lang.*'\nimport 'java.util.*'\nimport 'androlua.*'\n\nimport \"loadlayout\"\nimport \"loadbitmap\"\nimport \"loadmenu\"\n\nfunction enum(e)\n    return function()\n        if e.hasMoreElements() then\n            return e.nextElement()\n        end\n    end\nend\n\nfunction each(o)\n    local iter = o.iterator()\n    return function()\n        if iter.hasNext() then\n            return iter.next()\n        end\n    end\nend\n\nfunction dump(o)\n    local t = {}\n    local _t = {}\n    local _n = {}\n    local space, deep = string.rep(' ', 2), 0\n    local function _ToString(o, _k)\n        if type(o) == ('number') then\n            table.insert(t, o)\n        elseif type(o) == ('string') then\n            table.insert(t, string.format('%q', o))\n        elseif type(o) == ('table') then\n            local mt = getmetatable(o)\n            if mt and mt.__tostring then\n                table.insert(t, tostring(o))\n            else\n                deep = deep + 2\n                table.insert(t, '{')\n\n                for k, v in pairs(o) do\n                    if v == _G then\n                        table.insert(t, string.format('\\r\\n%s%s\\t=%s ;', string.rep(space, deep - 1), k, \"_G\"))\n                    elseif v ~= package.loaded then\n                        if tonumber(k) then\n                            k = string.format('[%s]', k)\n                        else\n                            k = string.format('[\\\"%s\\\"]', k)\n                        end\n                        table.insert(t, string.format('\\r\\n%s%s\\t= ', string.rep(space, deep - 1), k))\n                        if type(v) == ('table') then\n                            if _t[tostring(v)] == nil then\n                                _t[tostring(v)] = v\n                                local _k = _k .. k\n                                _t[tostring(v)] = _k\n                                _ToString(v, _k)\n                            else\n                                table.insert(t, tostring(_t[tostring(v)]))\n                                table.insert(t, ';')\n                            end\n                        else\n                            _ToString(v, _k)\n                        end\n                    end\n                end\n                table.insert(t, string.format('\\r\\n%s}', string.rep(space, deep - 1)))\n                deep = deep - 2\n            end\n        else\n            table.insert(t, tostring(o))\n        end\n        table.insert(t, \" ;\")\n        return t\n    end\n\n    t = _ToString(o, '')\n    return table.concat(t)\nend\n\nlocal NIL = {}\nsetmetatable(NIL, { __tostring = function() return \"nil\" end })\n\nlocal function printstack()\n    local stacks = {}\n    for m = 2, 16 do\n        local dbs = {}\n        local info = debug.getinfo(m)\n        if info == nil then\n            break\n        end\n        table.insert(stacks, dbs)\n        dbs.info = info\n        local func = info.func\n        local nups = info.nups\n        local ups = {}\n        dbs.upvalues = ups\n        for n = 1, nups do\n            local n, v = debug.getupvalue(func, n)\n            if v == nil then\n                v = NIL\n            end\n            if string.byte(n) == 40 then\n                if ups[n] == nil then\n                    ups[n] = {}\n                end\n                table.insert(ups[n], v)\n            else\n                ups[n] = v\n            end\n        end\n\n        local lps = {}\n        dbs.localvalues = lps\n        lps.vararg = {}\n        --lps.temporary={}\n        for n = -1, -255, -1 do\n            local k, v = debug.getlocal(m, n)\n            if k == nil then\n                break\n            end\n            if v == nil then\n                v = NIL\n            end\n            table.insert(lps.vararg, v)\n        end\n        for n = 1, 255 do\n            local n, v = debug.getlocal(m, n)\n            if n == nil then\n                break\n            end\n            if v == nil then\n                v = NIL\n            end\n            if string.byte(n) == 40 then\n                if lps[n] == nil then\n                    lps[n] = {}\n                end\n                table.insert(lps[n], v)\n            else\n                lps[n] = v\n            end\n            --table.insert(lps,string.format(\"%s=%s\",n,v))\n        end\n    end\n    print(dump(stacks))\n    -- print(\"info=\"..dump(dbs))\n    -- print(\"_ENV=\"..dump(ups._ENV or lps._ENV))\nend\n\nfunction getids()\n    return luajava.ids\nend\nlocal function setmetamethod(t, k, v)\n    getmetatable(t)[k] = v\nend\n\nlocal function getmetamethod(t, k, v)\n    return getmetatable(t)[k]\nend\n\nlocal function checkPath(path)\n    if path:find(\"^[^/][%w%./_%-]+$\") then\n        if not path:find(\"%.lua$\") then\n            path = string.format(\"%s/%s.lua\", activity.luaDir, path)\n        else\n            path = string.format(\"%s/%s\", activity.luaDir, path)\n        end\n    end\n    return path\nend\n\nlocal os_mt = {}\nos_mt.__index = function(t, k)\n    local _t = {}\n    _t.__cmd = (rawget(t, \"__cmd\") or \"\") .. k .. \" \"\n    setmetatable(_t, os_mt)\n    return _t\nend\nos_mt.__call = function(t, ...)\n    local cmd = t.__cmd .. table.concat({ ... }, \" \")\n    local p = io.popen(cmd)\n    local s = p:read(\"a\")\n    p:close()\n    return s\nend\nsetmetatable(os, os_mt)\n\nlocal luajava_mt = {\n    __index = function(t, k)\n        local b, ret = xpcall(function()\n            return bindClass((rawget(t, \"__name\") or \"\") .. k)\n        end,\n            function()\n                local p = {}\n                p.__name = (rawget(t, \"__name\") or \"\") .. k .. \".\"\n                setmetatable(p, luajava_mt)\n                return p\n            end)\n        rawset(t, k, ret)\n        return ret\n    end\n}\nsetmetatable(luajava, luajava_mt)\n\nreturn _G"
  },
  {
    "path": "lua_main/json.lua",
    "content": "-----------------------------------------------------------------------------\n-- JSON4Lua: JSON encoding / decoding support for the Lua language.\n-- json Module.\n-- Author: Craig Mason-Jones\n-- Homepage: http://github.com/craigmj/json4lua/\n-- Version: aaa.0.0\n-- This module is released under the MIT License (MIT).\n-- Please see LICENCE.txt for details.\n--\n-- USAGE:\n-- This module exposes two functions:\n-- json.encode(o)\n-- Returns the table / string / boolean / number / nil / json.null value as a JSON-encoded string.\n-- json.decode(json_string)\n-- Returns a Lua object populated with the data encoded in the JSON string json_string.\n--\n-- REQUIREMENTS:\n-- compat-5.aaa if using Lua 5.0\n--\n-- CHANGELOG\n-- 0.9.20 Introduction of local Lua functions for private functions (removed _ function prefix).\n-- Fixed Lua 5.aaa compatibility issues.\n-- Introduced json.null to have null values in associative arrays.\n-- json.encode() performance improvement (more than 50%) through table.concat rather than ..\n-- Introduced decode ability to ignore /**/ comments in the JSON string.\n-- 0.9.10 Fix to array encoding / decoding to correctly manage nil/null values in arrays.\n-----------------------------------------------------------------------------\n\n-----------------------------------------------------------------------------\n-- Imports and dependencies\n-----------------------------------------------------------------------------\nlocal math = require('math')\nlocal string = require(\"string\")\nlocal table = require(\"table\")\n\n-----------------------------------------------------------------------------\n-- Module declaration\n-----------------------------------------------------------------------------\nlocal json = {} -- Public namespace\nlocal json_private = {} -- Private namespace\n\n-- Public constants\njson.EMPTY_ARRAY = {}\njson.EMPTY_OBJECT = {}\n\n-- Public functions\n\n-- Private functions\nlocal decode_scanArray\nlocal decode_scanComment\nlocal decode_scanConstant\nlocal decode_scanNumber\nlocal decode_scanObject\nlocal decode_scanString\nlocal decode_scanWhitespace\nlocal encodeString\nlocal isArray\nlocal isEncodable\n\n-----------------------------------------------------------------------------\n-- PUBLIC FUNCTIONS\n-----------------------------------------------------------------------------\n--- Encodes an arbitrary Lua object / variable.\n-- @param v The Lua object / variable to be JSON encoded.\n-- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode)\nfunction json.encode(v)\n    -- Handle nil values\n    if v == nil then\n        return \"null\"\n    end\n\n    local vtype = type(v)\n\n    -- Handle strings\n    if vtype == 'string' then\n        return '\"' .. json_private.encodeString(v) .. '\"' -- Need to handle encoding in string\n    end\n\n    -- Handle booleans\n    if vtype == 'number' or vtype == 'boolean' then\n        return tostring(v)\n    end\n\n    -- Handle tables\n    if vtype == 'table' then\n        local rval = {}\n        -- Consider arrays separately\n        local bArray, maxCount = isArray(v)\n        if bArray then\n            for i = 1, maxCount do\n                table.insert(rval, json.encode(v[i]))\n            end\n        else -- An object, not an array\n            for i, j in pairs(v) do\n                if isEncodable(i) and isEncodable(j) then\n                    table.insert(rval, '\"' .. json_private.encodeString(i) .. '\":' .. json.encode(j))\n                end\n            end\n        end\n        if bArray then\n            return '[' .. table.concat(rval, ',') .. ']'\n        else\n            return '{' .. table.concat(rval, ',') .. '}'\n        end\n    end\n\n    -- Handle null values\n    if vtype == 'function' and v == json.null then\n        return 'null'\n    end\n\n    assert(false, 'encode attempt to encode unsupported type ' .. vtype .. ':' .. tostring(v))\nend\n\n\n--- Decodes a JSON string and returns the decoded value as a Lua data structure / value.\n-- @param s The string to scan.\n-- @param [startPos] Optional starting position where the JSON string is located. Defaults to aaa.\n-- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil,\n-- and the position of the first character after\n-- the scanned JSON object.\nfunction json.decode(s, startPos)\n    startPos = startPos and startPos or 1\n    startPos = decode_scanWhitespace(s, startPos)\n    assert(startPos <= string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']')\n    local curChar = string.sub(s, startPos, startPos)\n    -- Object\n    if curChar == '{' then\n        return decode_scanObject(s, startPos)\n    end\n    -- Array\n    if curChar == '[' then\n        return decode_scanArray(s, startPos)\n    end\n    -- Number\n    if string.find(\"+-0123456789.e\", curChar, 1, true) then\n        return decode_scanNumber(s, startPos)\n    end\n    -- String\n    if curChar == [[\"]] or curChar == [[']] then\n        return decode_scanString(s, startPos)\n    end\n    if string.sub(s, startPos, startPos + 1) == '/*' then\n        return json.decode(s, decode_scanComment(s, startPos))\n    end\n    -- Otherwise, it must be a constant\n    return decode_scanConstant(s, startPos)\nend\n\n--- The null function allows one to specify a null value in an associative array (which is otherwise\n-- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null }\nfunction json.null()\n    return json.null -- so json.null() will also return null ;-)\nend\n\n-----------------------------------------------------------------------------\n-- Internal, PRIVATE functions.\n-- Following a Python-like convention, I have prefixed all these 'PRIVATE'\n-- functions with an underscore.\n-----------------------------------------------------------------------------\n\n--- Scans an array from JSON into a Lua object\n-- startPos begins at the start of the array.\n-- Returns the array and the next starting position\n-- @param s The string being scanned.\n-- @param startPos The starting position for the scan.\n-- @return table, int The scanned array as a table, and the position of the next character to scan.\nfunction decode_scanArray(s, startPos)\n    local array = {} -- The return value\n    local stringLen = string.len(s)\n    assert(string.sub(s, startPos, startPos) == '[', 'decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\\n' .. s)\n    startPos = startPos + 1\n    -- Infinite loop for array elements\n    repeat\n        startPos = decode_scanWhitespace(s, startPos)\n        assert(startPos <= stringLen, 'JSON String ended unexpectedly scanning array.')\n        local curChar = string.sub(s, startPos, startPos)\n        if (curChar == ']') then\n            return array, startPos + 1\n        end\n        if (curChar == ',') then\n            startPos = decode_scanWhitespace(s, startPos + 1)\n        end\n        assert(startPos <= stringLen, 'JSON String ended unexpectedly scanning array.')\n        object, startPos = json.decode(s, startPos)\n        table.insert(array, object)\n    until false\nend\n\n--- Scans a comment and discards the comment.\n-- Returns the position of the next character following the comment.\n-- @param string s The JSON string to scan.\n-- @param int startPos The starting position of the comment\nfunction decode_scanComment(s, startPos)\n    assert(string.sub(s, startPos, startPos + 1) == '/*', \"decode_scanComment called but comment does not start at position \" .. startPos)\n    local endPos = string.find(s, '*/', startPos + 2)\n    assert(endPos ~= nil, \"Unterminated comment in string at \" .. startPos)\n    return endPos + 2\nend\n\n--- Scans for given constants: true, false or null\n-- Returns the appropriate Lua type, and the position of the next character to read.\n-- @param s The string being scanned.\n-- @param startPos The position in the string at which to start scanning.\n-- @return object, int The object (true, false or nil) and the position at which the next character should be\n-- scanned.\nfunction decode_scanConstant(s, startPos)\n    local consts = { [\"true\"] = true, [\"false\"] = false, [\"null\"] = nil }\n    local constNames = { \"true\", \"false\", \"null\" }\n\n    for i, k in pairs(constNames) do\n        if string.sub(s, startPos, startPos + string.len(k) - 1) == k then\n            return consts[k], startPos + string.len(k)\n        end\n    end\n    assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos)\nend\n\n--- Scans a number from the JSON encoded string.\n-- (in fact, also is able to scan numeric +- eqns, which is not\n-- in the JSON spec.)\n-- Returns the number, and the position of the next character\n-- after the number.\n-- @param s The string being scanned.\n-- @param startPos The position at which to start scanning.\n-- @return number, int The extracted number and the position of the next character to scan.\nfunction decode_scanNumber(s, startPos)\n    local endPos = startPos + 1\n    local stringLen = string.len(s)\n    local acceptableChars = \"+-0123456789.e\"\n    while (string.find(acceptableChars, string.sub(s, endPos, endPos), 1, true)\n            and endPos <= stringLen) do\n        endPos = endPos + 1\n    end\n    local stringValue = 'return ' .. string.sub(s, startPos, endPos - 1)\n    local stringEval = loadstring(stringValue)\n    assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos)\n    return stringEval(), endPos\nend\n\n--- Scans a JSON object into a Lua object.\n-- startPos begins at the start of the object.\n-- Returns the object and the next starting position.\n-- @param s The string being scanned.\n-- @param startPos The starting position of the scan.\n-- @return table, int The scanned object as a table and the position of the next character to scan.\nfunction decode_scanObject(s, startPos)\n    local object = {}\n    local stringLen = string.len(s)\n    local key, value\n    assert(string.sub(s, startPos, startPos) == '{', 'decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\\n' .. s)\n    startPos = startPos + 1\n    repeat\n        startPos = decode_scanWhitespace(s, startPos)\n        assert(startPos <= stringLen, 'JSON string ended unexpectedly while scanning object.')\n        local curChar = string.sub(s, startPos, startPos)\n        if (curChar == '}') then\n            return object, startPos + 1\n        end\n        if (curChar == ',') then\n            startPos = decode_scanWhitespace(s, startPos + 1)\n        end\n        assert(startPos <= stringLen, 'JSON string ended unexpectedly scanning object.')\n        -- Scan the key\n        key, startPos = json.decode(s, startPos)\n        assert(startPos <= stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)\n        startPos = decode_scanWhitespace(s, startPos)\n        assert(startPos <= stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)\n        assert(string.sub(s, startPos, startPos) == ':', 'JSON object key-value assignment mal-formed at ' .. startPos)\n        startPos = decode_scanWhitespace(s, startPos + 1)\n        assert(startPos <= stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key)\n        value, startPos = json.decode(s, startPos)\n        object[key] = value\n    until false -- infinite loop while key-value pairs are found\nend\n\n-- START SoniEx2\n-- Initialize some things used by decode_scanString\n-- You know, for efficiency\nlocal escapeSequences = {\n    [\"\\\\t\"] = \"\\t\",\n    [\"\\\\f\"] = \"\\f\",\n    [\"\\\\r\"] = \"\\r\",\n    [\"\\\\n\"] = \"\\n\",\n    [\"\\\\b\"] = \"\\b\"\n}\nsetmetatable(escapeSequences, {\n    __index = function(t, k)\n        -- skip \"\\\" aka strip escape\n        return string.sub(k, 2)\n    end\n})\n-- END SoniEx2\n\n--- Scans a JSON string from the opening inverted comma or single quote to the\n-- end of the string.\n-- Returns the string extracted as a Lua string,\n-- and the position of the next non-string character\n-- (after the closing inverted comma or single quote).\n-- @param s The string being scanned.\n-- @param startPos The starting position of the scan.\n-- @return string, int The extracted string as a Lua string, and the next character to parse.\nfunction decode_scanString(s, startPos)\n    assert(startPos, 'decode_scanString(..) called without start position')\n    local startChar = string.sub(s, startPos, startPos)\n    -- START SoniEx2\n    -- PS: I don't think single quotes are valid JSON\n    assert(startChar == [[\"]] or startChar == [[']], 'decode_scanString called for a non-string')\n    --assert(startPos, \"String decoding failed: missing closing \" .. startChar .. \" for string at position \" .. oldStart)\n    local t = {}\n    local i, j = startPos, startPos\n    while string.find(s, startChar, j + 1) ~= j + 1 do\n        local oldj = j\n        i, j = string.find(s, \"\\\\.\", j + 1)\n        local x, y = string.find(s, startChar, oldj + 1)\n        if not i or x < i then\n            i, j = x, y - 1\n        end\n        table.insert(t, string.sub(s, oldj + 1, i - 1))\n        if string.sub(s, i, j) == \"\\\\u\" then\n            local a = string.sub(s, j + 1, j + 4)\n            j = j + 4\n            local n = tonumber(a, 16)\n            assert(n, \"String decoding failed: bad Unicode escape \" .. a .. \" at position \" .. i .. \" : \" .. j)\n            -- math.floor(x/2^y) == lazy right shift\n            -- a % 2^b == bitwise_and(a, (2^b)-aaa)\n            -- 64 = 2^6\n            -- 4096 = 2^12 (or 2^6 * 2^6)\n            local x\n            if n < 0x80 then\n                x = string.char(n % 0x80)\n            elseif n < 0x800 then\n                -- [110x xxxx] [10xx xxxx]\n                x = string.char(0xC0 + (math.floor(n / 64) % 0x20), 0x80 + (n % 0x40))\n            else\n                -- [1110 xxxx] [10xx xxxx] [10xx xxxx]\n                x = string.char(0xE0 + (math.floor(n / 4096) % 0x10), 0x80 + (math.floor(n / 64) % 0x40), 0x80 + (n % 0x40))\n            end\n            table.insert(t, x)\n        else\n            table.insert(t, escapeSequences[string.sub(s, i, j)])\n        end\n    end\n    table.insert(t, string.sub(j, j + 1))\n    assert(string.find(s, startChar, j + 1), \"String decoding failed: missing closing \" .. startChar .. \" at position \" .. j .. \"(for string at position \" .. startPos .. \")\")\n    return table.concat(t, \"\"), j + 2\n    -- END SoniEx2\nend\n\n--- Scans a JSON string skipping all whitespace from the current start position.\n-- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached.\n-- @param s The string being scanned\n-- @param startPos The starting position where we should begin removing whitespace.\n-- @return int The first position where non-whitespace was encountered, or string.len(s)+aaa if the end of string\n-- was reached.\nfunction decode_scanWhitespace(s, startPos)\n    local whitespace = \" \\n\\r\\t\"\n    local stringLen = string.len(s)\n    while (string.find(whitespace, string.sub(s, startPos, startPos), 1, true) and startPos <= stringLen) do\n        startPos = startPos + 1\n    end\n    return startPos\nend\n\n--- Encodes a string to be JSON-compatible.\n-- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-)\n-- @param s The string to return as a JSON encoded (i.e. backquoted string)\n-- @return The string appropriately escaped.\n\nlocal escapeList = {\n    ['\"'] = '\\\\\"',\n    ['\\\\'] = '\\\\\\\\',\n    ['/'] = '\\\\/',\n    ['\\b'] = '\\\\b',\n    ['\\f'] = '\\\\f',\n    ['\\n'] = '\\\\n',\n    ['\\r'] = '\\\\r',\n    ['\\t'] = '\\\\t'\n}\n\nfunction json_private.encodeString(s)\n    local s = tostring(s)\n    return s:gsub(\".\", function(c) return escapeList[c] end) -- SoniEx2: 5.0 compat\nend\n\n-- Determines whether the given Lua type is an array or a table / dictionary.\n-- We consider any table an array if it has indexes aaa..n for its n items, and no\n-- other data in the table.\n-- I think this method is currently a little 'flaky', but can't think of a good way around it yet...\n-- @param t The table to evaluate as an array\n-- @return boolean, number True if the table can be represented as an array, false otherwise. If true,\n-- the second returned value is the maximum\n-- number of indexed elements in the array.\nfunction isArray(t)\n    -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable\n    -- (with the possible exception of 'n')\n    if (t == json.EMPTY_ARRAY) then return true, 0 end\n    if (t == json.EMPTY_OBJECT) then return false end\n\n    local maxIndex = 0\n    for k, v in pairs(t) do\n        if (type(k) == 'number' and math.floor(k) == k and 1 <= k) then -- k,v is an indexed pair\n            if (not isEncodable(v)) then return false end -- All array elements must be encodable\n            maxIndex = math.max(maxIndex, k)\n        else\n            if (k == 'n') then\n                if v ~= (t.n or #t) then return false end -- False if n does not hold the number of elements\n            else -- Else of (k=='n')\n                if isEncodable(v) then return false end\n            end -- End of (k~='n')\n        end -- End of k,v not an indexed pair\n    end -- End of loop across all pairs\n    return true, maxIndex\nend\n\n--- Determines whether the given Lua object / table / variable can be JSON encoded. The only\n-- types that are JSON encodable are: string, boolean, number, nil, table and json.null.\n-- In this implementation, all other types are ignored.\n-- @param o The object to examine.\n-- @return boolean True if the object should be JSON encoded, false if it should be ignored.\nfunction isEncodable(o)\n    local t = type(o)\n    return (t == 'string' or t == 'boolean' or t == 'number' or t == 'nil' or t == 'table') or\n            (t == 'function' and o == json.null)\nend\n\nreturn json"
  },
  {
    "path": "lua_main/loadbitmap.lua",
    "content": "local context = activity or service\n\nlocal LuaBitmap = luajava.bindClass \"androlua.LuaBitmap\"\nlocal function loadbitmap(path)\n    if not path:find(\"^https*://\") and not path:find(\"%.%a%a%a%a?$\") then\n        path = path .. \".png\"\n    end\n    if path:find(\"^https*://\") then\n        return LuaBitmap.getHttpBitmap(context, path)\n    elseif not path:find(\"^/\") then\n        return LuaBitmap.getLoacalBitmap(context, string.format(\"%s/%s\", luajava.luadir, path))\n    else\n        return LuaBitmap.getLoacalBitmap(context, path)\n    end\nend\n\nreturn loadbitmap\n"
  },
  {
    "path": "lua_main/loadlayout.lua",
    "content": "local require = require\nlocal table = require \"table\"\nluajava.package = luajava.package or {}\nluajava.loaded = luajava.loaded or {}\nluajava.ids = luajava.ids or { id = 0x7f000000 }\nlocal packages = luajava.package\nlocal loaded = luajava.loaded\nlocal ids = luajava.ids\nlocal _G = _G\nlocal insert = table.insert\nlocal new = luajava.new\nlocal bindClass = luajava.bindClass\nlocal ltrs = {}\n\nlocal context = activity or service\n\nlocal String = bindClass(\"java.lang.String\")\nlocal Context = bindClass(\"android.content.Context\")\nlocal ViewGroup = bindClass(\"android.view.ViewGroup\")\nlocal View = bindClass(\"android.view.View\")\nlocal Gravity = bindClass(\"android.view.Gravity\")\nlocal OnClickListener = bindClass(\"android.view.View$OnClickListener\")\nlocal TypedValue = bindClass(\"android.util.TypedValue\")\nlocal BitmapDrawable = bindClass(\"android.graphics.drawable.BitmapDrawable\")\nlocal NineBitmapDrawable = bindClass(\"androlua.NineBitmapDrawable\")\n--local ArrayListAdapter = bindClass(\"android.widget.ArrayListAdapter\")\n--local ArrayPageAdapter = bindClass(\"android.widget.ArrayPageAdapter\")\nlocal ScaleType = bindClass(\"android.widget.ImageView$ScaleType\")\nlocal TruncateAt = bindClass(\"android.text.TextUtils$TruncateAt\")\nlocal DisplayMetrics = bindClass(\"android.util.DisplayMetrics\")\nlocal android_R = bindClass(\"android.R\")\nlocal LuaDrawable = bindClass(\"androlua.LuaDrawable\")\nlocal ImageLoader = bindClass(\"androlua.LuaImageLoader\")\nlocal Build = bindClass(\"android.os.Build\")\n\nlocal ver = Build.VERSION.SDK_INT\n\nandroid = { R = android_R }\nlocal scaleTypes = ScaleType.values()\n\nlocal wm = context.getSystemService(Context.WINDOW_SERVICE);\nlocal outMetrics = DisplayMetrics();\nwm.getDefaultDisplay().getMetrics(outMetrics);\nlocal W = outMetrics.widthPixels;\nlocal H = outMetrics.heightPixels;\n\nlocal function alyloader(path)\n    local alypath = package.path:gsub(\"%.lua;\", \".aly;\")\n    local path, msg = package.searchpath(path, alypath)\n    if msg then\n        return msg\n    end\n    local f = io.open(path)\n    local s = f:read(\"*a\")\n    f:close()\n    if string.sub(s, 1, 4) == \"\\27Lua\" then\n        return assert(loadfile(path)), path\n    else\n        --return assert(loadstring(\"return \"..s, path:match(\"[^/]+/[^/]+$\"),\"bt\")),path\n        local f, st = loadstring(\"return \" .. s, path:match(\"[^/]+/[^/]+$\"), \"bt\")\n        if st then\n            error(st:gsub(\"%b[]\", path, 1), 0)\n        end\n        return f, st\n    end\nend\n\ntable.insert(package.searchers, alyloader)\n\nlocal dm = context.getResources().getDisplayMetrics()\nlocal id = 0x7f000000\nlocal toint = {\n    --android:drawingCacheQuality\n    auto = 0,\n    low = 1,\n    high = 2,\n\n    --android:importantForAccessibility\n    auto = 0,\n    yes = 1,\n    no = 2,\n\n    --android:layerType\n    none = 0,\n    software = 1,\n    hardware = 2,\n\n    --android:layoutDirection\n    ltr = 0,\n    rtl = 1,\n    inherit = 2,\n    locale = 3,\n\n    --android:scrollbarStyle\n    insideOverlay = 0x0,\n    insideInset = 0x01000000,\n    outsideOverlay = 0x02000000,\n    outsideInset = 0x03000000,\n\n    --android:visibility\n    visible = 0,\n    invisible = 4,\n    gone = 8,\n    wrap_content = -2,\n    fill_parent = -1,\n    match_parent = -1,\n    wrap = -2,\n    fill = -1,\n    match = -1,\n\n    --android:autoLink\n    none = 0x00,\n    web = 0x01,\n    email = 0x02,\n    phon = 0x04,\n    map = 0x08,\n    all = 0x0f,\n\n    --android:orientation\n    vertical = 1,\n    horizontal = 0,\n\n    --android:gravity\n    axis_clip = 8,\n    axis_pull_after = 4,\n    axis_pull_before = 2,\n    axis_specified = 1,\n    axis_x_shift = 0,\n    axis_y_shift = 4,\n    bottom = 80,\n    center = 17,\n    center_horizontal = 1,\n    center_vertical = 16,\n    clip_horizontal = 8,\n    clip_vertical = 128,\n    display_clip_horizontal = 16777216,\n    display_clip_vertical = 268435456,\n    --fill = 119,\n    fill_horizontal = 7,\n    fill_vertical = 112,\n    horizontal_gravity_mask = 7,\n    left = 3,\n    no_gravity = 0,\n    relative_horizontal_gravity_mask = 8388615,\n    relative_layout_direction = 8388608,\n    right = 5,\n    start = 8388611,\n    top = 48,\n    vertical_gravity_mask = 112,\n    [\"end\"] = 8388613,\n\n    --android:textAlignment\n    inherit = 0,\n    gravity = 1,\n    textStart = 2,\n    textEnd = 3,\n    textCenter = 4,\n    viewStart = 5,\n    viewEnd = 6,\n\n    --android:inputType\n    none = 0x00000000,\n    text = 0x00000001,\n    textCapCharacters = 0x00001001,\n    textCapWords = 0x00002001,\n    textCapSentences = 0x00004001,\n    textAutoCorrect = 0x00008001,\n    textAutoComplete = 0x00010001,\n    textMultiLine = 0x00020001,\n    textImeMultiLine = 0x00040001,\n    textNoSuggestions = 0x00080001,\n    textUri = 0x00000011,\n    textEmailAddress = 0x00000021,\n    textEmailSubject = 0x00000031,\n    textShortMessage = 0x00000041,\n    textLongMessage = 0x00000051,\n    textPersonName = 0x00000061,\n    textPostalAddress = 0x00000071,\n    textPassword = 0x00000081,\n    textVisiblePassword = 0x00000091,\n    textWebEditText = 0x000000a1,\n    textFilter = 0x000000b1,\n    textPhonetic = 0x000000c1,\n    textWebEmailAddress = 0x000000d1,\n    textWebPassword = 0x000000e1,\n    number = 0x00000002,\n    numberSigned = 0x00001002,\n    numberDecimal = 0x00002002,\n    numberPassword = 0x00000012,\n    phone = 0x00000003,\n    datetime = 0x00000004,\n    date = 0x00000014,\n    time = 0x00000024,\n\n    --android:imeOptions\n    normal = 0x00000000,\n    actionUnspecified = 0x00000000,\n    actionNone = 0x00000001,\n    actionGo = 0x00000002,\n    actionSearch = 0x00000003,\n    actionSend = 0x00000004,\n    actionNext = 0x00000005,\n    actionDone = 0x00000006,\n    actionPrevious = 0x00000007,\n    flagNoFullscreen = 0x2000000,\n    flagNavigatePrevious = 0x4000000,\n    flagNavigateNext = 0x8000000,\n    flagNoExtractUi = 0x10000000,\n    flagNoAccessoryAction = 0x20000000,\n    flagNoEnterAction = 0x40000000,\n    flagForceAscii = 0x80000000,\n}\n\nlocal scaleType = {\n    --android:scaleType\n    matrix = 0,\n    fitXY = 1,\n    fitStart = 2,\n    fitCenter = 3,\n    fitEnd = 4,\n    center = 5,\n    centerCrop = 6,\n    centerInside = 7,\n}\n\nlocal rules = {\n    layout_above = 2,\n    layout_alignBaseline = 4,\n    layout_alignBottom = 8,\n    layout_alignEnd = 19,\n    layout_alignLeft = 5,\n    layout_alignParentBottom = 12,\n    layout_alignParentEnd = 21,\n    layout_alignParentLeft = 9,\n    layout_alignParentRight = 11,\n    layout_alignParentStart = 20,\n    layout_alignParentTop = 10,\n    layout_alignRight = 7,\n    layout_alignStart = 18,\n    layout_alignTop = 6,\n    layout_alignWithParentIfMissing = 0,\n    layout_below = 3,\n    layout_centerHorizontal = 14,\n    layout_centerInParent = 13,\n    layout_centerVertical = 15,\n    layout_toEndOf = 17,\n    layout_toLeftOf = 0,\n    layout_toRightOf = 1,\n    layout_toStartOf = 16\n}\n\nlocal types = {\n    px = 0,\n    dp = 1,\n    sp = 2,\n    pt = 3,\n    [\"in\"] = 4,\n    mm = 5\n}\n\nlocal function checkType(v)\n    local n, ty = string.match(v, \"^(%-?[%.%d]+)(%a%a)$\")\n    return tonumber(n), types[ty]\nend\n\nlocal function checkPercent(v)\n    local n, ty = string.match(v, \"^(%-?[%.%d]+)%%([wh])$\")\n    if ty == nil then\n        return nil\n    elseif ty == \"w\" then\n        return tonumber(n) * W / 100\n    elseif ty == \"h\" then\n        return tonumber(n) * H / 100\n    end\nend\n\nlocal function split(s, t)\n    local idx = 1\n    local l = #s\n    return function()\n        local i = s:find(t, idx)\n        if idx >= l then\n            return nil\n        end\n        if i == nil then\n            i = l + 1\n        end\n        local sub = s:sub(idx, i - 1)\n        idx = i + 1\n        return sub\n    end\nend\n\nlocal function checkint(s)\n    local ret = 0\n    for n in split(s, \"|\") do\n        if toint[n] then\n            ret = bit.bor(ret, toint[n])\n        else\n            return nil\n        end\n    end\n    return ret\nend\n\nlocal function checkNumber(var)\n    if type(var) == \"string\" then\n        if var == \"true\" then\n            return true\n        elseif var == \"false\" then\n            return false\n        end\n\n        if toint[var] then\n            return toint[var]\n        end\n\n        local p = checkPercent(var)\n        if p then\n            return p\n        end\n\n        local i = checkint(var)\n        if i then\n            return i\n        end\n\n        local h = string.match(var, \"^#(%x+)$\")\n        if h then\n            local c = tonumber(h, 16)\n            if c then\n                if #h <= 6 then\n                    return c - 0x1000000\n                elseif #h <= 8 then\n                    if c > 0x7fffffff then\n                        return c - 0x100000000\n                    else\n                        return c\n                    end\n                end\n            end\n        end\n\n        local n, ty = checkType(var)\n        if ty then\n            return TypedValue.applyDimension(ty, n, dm)\n        end\n    end\n    -- return var\nend\n\nlocal function checkValue(var)\n    return tonumber(var) or checkNumber(var) or var\nend\n\nlocal function checkValues(...)\n    local vars = { ... }\n    for n = 1, #vars do\n        vars[n] = checkValue(vars[n])\n    end\n    return unpack(vars)\nend\n\nlocal function getattr(s)\n    return android_R.attr[s]\nend\n\nlocal function checkattr(s)\n    local e, s = pcall(getattr, s)\n    if e then\n        return s\n    end\n    return nil\nend\n\n\n-- 获取类似 @drawable/ic_back 的资源\nlocal function getIdentifier(type, name) -- drawable  ic_back\n    return context.getResources().getIdentifier(name, type, context.getPackageName())\nend\n\nlocal function dump2(t)\n    local _t = {}\n    table.insert(_t, tostring(t))\n    table.insert(_t, \"\\t{\")\n    for k, v in pairs(t) do\n        if type(v) == \"table\" then\n            table.insert(_t, \"\\t\\t\" .. tostring(k) .. \"={\" .. tostring(v[1]) .. \" ...}\")\n        else\n            table.insert(_t, \"\\t\\t\" .. tostring(k) .. \"=\" .. tostring(v))\n        end\n    end\n    table.insert(_t, \"\\t}\")\n    t = table.concat(_t, \"\\n\")\n    return t\nend\n\nlocal function getStatusBarHeight()\n    local identifier = context.getResources().getIdentifier(\"status_bar_height\", \"dimen\", \"android\")\n    if identifier > 0 then\n        return context.getResources().getDimensionPixelSize(identifier)\n    end\n    return 0\nend\n\nlocal function setStatusBarColorTrans()\n    if activity then\n        activity.setStatusBarColor(0x00000000)\n    end\nend\n\nlocal function addStatusBar(parent, color)\n    if ver >= 21 then\n        local statusbBar = View(context)\n        statusbBar.setBackgroundColor(color)\n        local height = getStatusBarHeight()\n        local params = ViewGroup.LayoutParams(-1, height) --设置layout属性\n        statusbBar.setLayoutParams(params)\n        -- statusbBar.setTranslationZ(checkNumber(\"2dp\"))\n        parent.addView(statusbBar, 0)\n        pcall(setStatusBarColorTrans)\n    end\nend\n\nlocal function setBackground(view, bg)\n    if ver < 16 then\n        view.setBackgroundDrawable(bg)\n    else\n        view.setBackground(bg)\n    end\nend\n\nlocal function setElevation(view, v)\n    if ver >= 21 then\n        view.setElevation(checkValue(v))\n    end\nend\n\nlocal function setLineSpacing(textView, v)\n    if ver >= 16 then\n        textView.setLineSpacing(textView.getLineSpacingExtra(), v);\n    end\nend\n\nlocal function setattribute(root, view, params, k, v, ids)\n    if k == \"layout_x\" then\n        params.x = checkValue(v)\n    elseif k == \"layout_y\" then\n        params.y = checkValue(v)\n    elseif k == \"layout_weight\" then\n        params.weight = checkValue(v)\n    elseif k == \"layout_gravity\" then\n        params.gravity = checkValue(v)\n    elseif k == \"layout_marginStart\" then\n        params.setMarginStart(checkValue(v))\n    elseif k == \"layout_marginEnd\" then\n        params.setMarginEnd(checkValue(v))\n    elseif k == \"statusBarColor\" then\n        if v:find(\"^#\") then\n            addStatusBar(view, checkNumber(v))\n        end\n    elseif rules[k] and (v == true or v == \"true\") then\n        params.addRule(rules[k])\n    elseif rules[k] then\n        params.addRule(rules[k], ids[v])\n    elseif type(k) == \"string\" and k:find(\"^applayout_\") then\n        k = string.gsub(k, \"^applayout_(%w)\", function(s) return string.upper(s) end)\n        params[\"set\" .. k](v)\n    elseif k == \"items\" and type(v) == \"table\" then --创建列表项目\n        --        local adapter = ArrayListAdapter(context, android_R.layout.simple_list_item_1, String(v))\n        --        view.setAdapter(adapter)\n    elseif k == \"pages\" and type(v) == \"table\" then --创建页项目\n        local ps = {}\n        for n, o in ipairs(v) do\n            local tp = type(o)\n            if tp == \"string\" or tp == \"table\" then\n                table.insert(ps, loadlayout(o, root))\n            else\n                table.insert(ps, o)\n            end\n        end\n        --        local adapter = ArrayPageAdapter(View(ps))\n        --        view.setAdapter(adapter)\n    elseif k == \"textSize\" then\n        if tonumber(v) then\n            view.setTextSize(tonumber(v))\n        elseif type(v) == \"string\" then\n            local n, ty = checkType(v)\n            if ty then\n                view.setTextSize(ty, n)\n            else\n                view.setTextSize(v)\n            end\n        else\n            view.setTextSize(v)\n        end\n    elseif k == \"textAppearance\" then\n        view.setTextAppearance(context, checkattr(v))\n    elseif k == \"lineSpacingMultiplier\" then\n        setLineSpacing(view, tonumber(v))\n    elseif k == \"ellipsize\" then\n        view.setEllipsize(TruncateAt[string.upper(v)])\n    elseif k == \"url\" then\n        view.loadUrl(url)\n    elseif k == \"src\" then\n        if v:find('^@') then -- @drawable/ic_back\n            local index = v:find('/')\n            view.setImageResource(getIdentifier(v:sub(2, index - 1), v:sub(index + 1, -1)))\n        else\n            ImageLoader.load(view, v)\n        end\n    elseif k == \"elevation\" then\n        setElevation(view, v)\n    elseif k == \"scaleType\" then\n        view.setScaleType(scaleTypes[scaleType[v]])\n    elseif k == \"background\" then\n        if type(v) == \"string\" then\n            if v:find('^@') then\n                local index = v:find('/')\n                view.setBackgroundResource(getIdentifier(v:sub(2, index - 1), v:sub(index + 1, -1)))\n            elseif v:find(\"^#\") then\n                view.setBackgroundColor(checkNumber(v))\n            elseif rawget(root, v) or rawget(_G, v) then\n                v = rawget(root, v) or rawget(_G, v)\n                if type(v) == \"function\" then -- 自定义 drawable\n                    setBackground(view, LuaDrawable(v))\n                elseif type(v) == \"userdata\" then\n                    setBackground(view, v)\n                end\n            else\n                if (not v:find(\"^/\")) and luadir then\n                    v = luadir .. v\n                end\n                if v:find(\"%.9%.png\") then\n                    setBackground(view, NineBitmapDrawable(loadbitmap(v)))\n                else\n                    setBackground(view, BitmapDrawable(loadbitmap(v)))\n                end\n            end\n        elseif type(v) == \"userdata\" then\n            setBackground(view, v)\n        elseif type(v) == \"number\" then\n            setBackground(view, v)\n        end\n    elseif k == \"onClick\" then --设置onClick事件接口\n        local listener\n        if type(v) == \"function\" then\n            listener = OnClickListener { onClick = v }\n        elseif type(v) == \"userdata\" then\n            listener = v\n        elseif type(v) == \"string\" then\n            if ltrs[v] then\n                listener = ltrs[v]\n            else\n                local l = rawget(root, v) or rawget(_G, v)\n                if type(l) == \"function\" then\n                    listener = OnClickListener { onClick = l }\n                elseif type(l) == \"userdata\" then\n                    listener = l\n                else\n                    listener = OnClickListener { onClick = function(a) (root[v] or _G[v])(a) end }\n                end\n                ltrs[v] = listener\n            end\n        end\n        view.setOnClickListener(listener)\n    elseif k == \"password\" and (v == \"true\" or v == true) then\n        view.setInputType(0x81)\n    elseif type(k) == \"string\" and not (k:find(\"layout_\")) and not (k:find(\"padding\")) and k ~= \"style\" then --设置属性\n        k = string.gsub(k, \"^(%w)\", function(s) return string.upper(s) end)\n        if k == \"Text\" or k == \"Title\" or k == \"Subtitle\" then\n            view[\"set\" .. k](v)\n        else\n            view[\"set\" .. k](checkValue(v))\n        end\n    end\nend\n\nlocal function copytable(f, t, b)\n    for k, v in pairs(f) do\n        if k == 1 then\n        elseif b or t[k] == nil then\n            t[k] = v\n        end\n    end\nend\n\n\nlocal function loadlayout(t, root, group)\n    if type(t) == \"string\" then\n        t = require(t)\n    elseif type(t) ~= \"table\" then\n        error(string.format(\"loadlayout error: Fist value Must be a table, checked import layout.\", 0))\n    end\n    root = root or _G\n    local view, style\n\n    if t.style then\n        if t.style:find('^@') then\n            local index = t.style:find('/')\n            style = getIdentifier(t.style:sub(2, index - 1), t.style:sub(index + 1, -1))\n        else\n            local st, sty = pcall(require, t.style)\n            if st then\n                copytable(sty, t)\n            else\n                style = checkattr(t.style)\n            end\n        end\n    end\n    if not t[1] then\n        error(string.format(\"loadlayout error: Fist value Must be a Class, checked import package.\\n\\tat %s\", dump2(t)), 0)\n    end\n\n    if style then\n        view = t[1](context, nil, style) -- 第3个构造方法\n    else\n        view = t[1](context) --创建view\n    end\n\n    local params = ViewGroup.LayoutParams(checkValue(t.layout_width) or -2, checkValue(t.layout_height) or -2) --设置layout属性\n    if group then\n        params = group.LayoutParams(params)\n    end\n    --设置layout_margin属性\n    if t.layout_margin or t.layout_marginStart or t.layout_marginEnd or t.layout_marginLeft or t.layout_marginTop or t.layout_marginRight or t.layout_marginBottom then\n        params.setMargins(checkValues(t.layout_marginLeft or t.layout_margin or 0, t.layout_marginTop or t.layout_margin or 0, t.layout_marginRight or t.layout_margin or 0, t.layout_marginBottom or t.layout_margin or 0))\n    end\n\n    --设置padding属性\n    if t.padding or t.paddingLeft or t.paddingTop or t.paddingRight or t.paddingBottom then\n        view.setPadding(checkValues(t.paddingLeft or t.padding or 0, t.paddingTop or t.padding or 0, t.paddingRight or t.padding or 0, t.paddingBottom or t.padding or 0))\n    end\n    if t.paddingStart or t.paddingEnd then\n        view.setPaddingRelative(checkValues(t.paddingStart or t.padding or 0, t.paddingTop or t.padding or 0, t.paddingEnd or t.padding or 0, t.paddingBottom or t.padding or 0))\n    end\n\n    for k, v in pairs(t) do\n        if tonumber(k) and (type(v) == \"table\" or type(v) == \"string\") then --创建子view\n            view.addView(loadlayout(v, root, t[1]))\n        elseif k == \"id\" then --创建view的全局变量\n            rawset(root, v, view)\n            local id = ids.id\n            ids.id = ids.id + 1\n            view.setId(id)\n            ids[v] = id\n\n        else\n            local e, s = pcall(setattribute, root, view, params, k, v, ids)\n            if not e then\n                local _, i = s:find(\":%d+:\")\n                s = s:sub(i or 1, -1)\n                print(string.format(\"loadlayout error %s \\n\\tat %s\\n\\tat  key=%s value=%s\\n\\tat %s\", s, view.toString(), k, v, dump2(t)), 0)\n            end\n        end\n    end\n\n    --if group then\n    --group.addView(view,params)\n    --else\n    view.setLayoutParams(params)\n    return view\n    --end\nend\n\n\nreturn loadlayout\n"
  },
  {
    "path": "lua_main/loadmenu.lua",
    "content": "local require = require\nlocal table = require \"table\"\nluajava.package = luajava.package or {}\nluajava.loaded = luajava.loaded or {}\nluajava.ids = luajava.ids or { id = 0x7f000000 }\nlocal packages = luajava.package\nlocal loaded = luajava.loaded\nlocal ids = luajava.ids\nlocal _G = _G\nlocal insert = table.insert\nlocal new = luajava.new\nlocal bindClass = luajava.bindClass\nlocal LuaDrawable = luajava.bindClass \"androlua.LuaDrawable\"\nlocal loadbitmap = require \"loadbitmap\"\n\nlocal function loadmenu(menu, t, root)\n    root = root or _G\n    for k, v in ipairs(t) do\n        local id = ids.id\n        ids.id = ids.id + 1\n        if v[1] == MenuItem then\n            local item = menu.add(v.group or 0, id, v.order or 0, v.title)\n            if v.id then\n                rawset(root, v.id, item)\n                ids[v.id] = id\n            end\n            item.setShowAsAction(1)\n            if v.icon then\n                item.setIcon(BitmapDrawable(loadbitmap(v.icon)))\n            end\n            if v.enabled == false then\n                item.setEnabled(v.enabled)\n            end\n            if v.visible == false then\n                item.setVisible(v.visible)\n            end\n        elseif v[1] == SubMenu then\n            local item = menu.addSubMenu(v.group or 0, id, v.order or 0, v.title)\n            item.HeaderTitle = v.title\n            loadmenu(item, v, root)\n        end\n    end\nend\n\nreturn loadmenu\n\n"
  },
  {
    "path": "lua_main/log.lua",
    "content": "--\n-- Created by IntelliJ IDEA.  Copyright (C) 2017 Hanks\n-- User: hanks\n-- Date: 2017/5/16\n-- Time: 10:44\n--\n\n-- print table content\nlocal function print_r(sth)\n    if type(sth) ~= \"table\" then\n        print(sth)\n        return\n    end\n\n    local space, deep = string.rep(' ', 4), 0\n    local function _dump(t)\n        local temp = {}\n        for k, v in pairs(t) do\n            local key = tostring(k)\n\n            if type(v) == \"table\" then\n                deep = deep + 2\n                print(string.format(\"%s[%s] => Table%s{\\n\",\n                    string.rep(space, deep - 1),\n                    key,\n                    string.rep(space, deep))) --print.\n                _dump(v)\n\n                print(string.format(\"%s)\", string.rep(space, deep)))\n                deep = deep - 2\n            else\n                print(string.format(\"%s[%s] => %s\",\n                    string.rep(space, deep + 1),\n                    key,\n                    v)) --print.\n            end\n        end\n    end\n\n    print(string.format(\"Table {\\n\"))\n    _dump(sth)\n    print(string.format(\"}\"))\nend\n\nlocal log = {}\nlog.print_r = print_r\nreturn log\n"
  },
  {
    "path": "lua_main/main.lua",
    "content": "require \"import\"\nimport \"android.widget.*\"\nimport \"android.content.*\"\nimport \"android.view.View\"\nimport \"android.support.v4.view.ViewPager\"\nimport \"android.support.v7.widget.Toolbar\"\nimport \"androlua.LuaActivity\"\nimport \"androlua.LuaAdapter\"\nimport \"androlua.LuaImageLoader\"\nimport \"androlua.common.LuaFileUtils\"\nimport \"androlua.LuaHttp\"\nimport \"java.io.File\"\nimport \"android.os.Build\"\nimport \"android.graphics.drawable.ColorDrawable\"\nimport \"android.graphics.drawable.GradientDrawable\"\nimport \"android.support.v7.widget.RecyclerView\"\nimport \"androlua.adapter.LuaRecyclerAdapter\"\nimport \"androlua.adapter.LuaRecyclerHolder\"\nimport \"android.support.v7.widget.GridLayoutManager\"\nimport \"android.support.v7.widget.helper.ItemTouchHelper\"\nimport \"pub.hanks.sample.adapter.DragTouchHelper\"\nimport \"android.support.design.widget.BottomSheetBehavior\"\nimport \"android.support.design.widget.CoordinatorLayout\"\nimport \"android.support.v4.view.MotionEventCompat\"\nimport \"android.view.MotionEvent\"\nimport \"android.support.design.widget.TabLayout\"\nimport \"androlua.adapter.LuaFragmentPageAdapter\"\n\nlocal uihelper = require \"uihelper\"\nlocal JSON = require \"cjson\"\nlocal md5 = require \"md5\"\nlocal adapter\nlocal touchHelper\nlocal adapterAll\nlocal touchHelperAll\nlocal sp = activity.getSharedPreferences(\"luandroid\", Context.MODE_PRIVATE)\nlocal home_bg\n\nactivity.setSwipeBackEnable(false)\n\nlocal bottomBehavior = BottomSheetBehavior()\nbottomBehavior.setPeekHeight(uihelper.dp2px(32))\n\nlocal homeFragment, homeAdapter, homeGetData, homeIconIsDraggin, homeIconsSetDragging = (require \"fragment_home\").newInstance()\nlocal listFragment, listAdapter, listGetData, listIconIsDraggin, listIconsSetDragging = (require \"fragment_list\").newInstance()\n\nlocal data = {\n    titles = { \"home\", \"list\" },\n    fragments = { homeFragment, listFragment },\n}\n\nlocal root_layout = {\n    FrameLayout,\n    layout_width = \"fill\",\n    layout_height = \"fill\",\n    {\n        ImageView,\n        id = \"iv_home_bg\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        scaleType = \"centerCrop\",\n    },\n    {\n        View,\n        id = \"layout_container\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n        background = \"#FAFFFFFF\",\n    },\n    {\n        ViewPager,\n        id = \"viewPager\",\n        layout_width = \"fill\",\n        layout_height = \"fill\",\n    },\n}\n\n\nlocal function downloadSplash(item)\n    if item.img == nil then return end\n    local dir = activity.getExternalFilesDir(\"splash\").getAbsolutePath()\n    if not File(dir).exists() then\n        File(dir).mkdirs()\n    end\n    local path = dir .. \"/\" .. md5.sumhexa(item.img);\n    if File(path).exists() then\n        item.img = path\n        sp.edit().putString(\"splash\", JSON.encode(item)).apply()\n        return\n    end\n    local options = {\n        url = item.img,\n        outputFile = path,\n    }\n    LuaHttp.request(options, function(e, code, body)\n        if e or code ~= 200 then return end\n        if File(path).exists() then\n            item.img = path\n            sp.edit().putString(\"splash\", JSON.encode(item)).apply()\n        end\n    end)\nend\n\nlocal function initSplash()\n    if not LuaUtil.isWifi() then return end\n    local today = os.date('%Y%m%d')\n    local url = 'https://coding.net/u/zhangyuhan/p/api_luanroid/git/raw/master/api/splash'\n    LuaHttp.request({ url = url }, function(e, code, body)\n        if e or code ~= 200 then return end\n        local arr = JSON.decode(body).data\n        local haveSplash = false\n        for i = 1, #arr do\n            if arr[i].date == today then\n                haveSplash = true\n                downloadSplash(arr[i])\n                return\n            end\n        end\n        if haveSplash == false then\n            downloadSplash(arr[#arr])\n        end\n    end)\nend\n\n\nlocal pageAdapter = LuaFragmentPageAdapter(activity.getSupportFragmentManager(),\n    luajava.createProxy(\"androlua.adapter.LuaFragmentPageAdapter$AdapterCreator\", {\n        getCount = function() return #data.fragments end,\n        getItem = function(position)\n            position = position + 1\n            return data.fragments[position]\n        end,\n        getPageTitle = function(position)\n            position = position + 1\n            return data.titles[position]\n        end\n    }))\n\nlocal function refreshData()\n    viewPager.postDelayed(luajava.createProxy('java.lang.Runnable', {\n        run = function()\n            if viewPager.getCurrentItem() == 0 then\n                homeGetData()\n            elseif position == 1 then\n                listGetData()\n            end\n        end\n    }), 500)\nend\n\nfunction onCreate(savedInstanceState)\n    activity.setLightStatusBar()\n    activity.setContentView(loadlayout(root_layout))\n    activity.disableDrawer()\n    viewPager.setAdapter(pageAdapter)\n    viewPager.setOffscreenPageLimit(#data.fragments)\n    viewPager.setCurrentItem(0)\n    viewPager.addOnPageChangeListener(luajava.createProxy('android.support.v4.view.ViewPager$OnPageChangeListener', {\n        onPageSelected = function(position)\n            refreshData()\n        end\n    }))\n\n    initSplash()\nend\n\nfunction onResume()\n    local config = JSON.decode(sp.getString('config', '{}'))\n\n    -- bg\n    if config.home_bg and config.home_bg ~= '' then\n        activity.setStatusBarColor(0x00FFFFFF)\n        LuaImageLoader.load(iv_home_bg, config.home_bg)\n    else\n        activity.setLightStatusBar()\n        iv_home_bg.setImageDrawable(ColorDrawable(0xFFFFFFFF))\n    end\n\n    local alpah = tonumber(config.home_bg_alpha or 9)\n    if alpah then\n        layout_container.setAlpha(alpah / 10)\n    end\n\n    if config.home_bg_alpha and config.home_bg_alpha ~= '' then\n        local alpah = tonumber(config.home_bg_alpha) or 9\n        if alpah then\n            layout_container.setAlpha(alpah / 10)\n        end\n    end\n\n    refreshData()\nend\n\nlocal mHits = { 0, 0 }\nimport \"android.os.SystemClock\"\nfunction onBackPressed()\n\n    print(homeIconIsDraggin())\n    if homeIconIsDraggin() then\n        homeIconsSetDragging(false)\n        homeAdapter.notifyDataSetChanged()\n        listAdapter.notifyDataSetChanged()\n        return true\n    end\n    print(listIconIsDraggin())\n\n    if listIconIsDraggin() then\n        listIconsSetDragging(false)\n        homeAdapter.notifyDataSetChanged()\n        listAdapter.notifyDataSetChanged()\n        return true\n    end\n\n    if viewPager.getCurrentItem() ~= 0 then\n        viewPager.setCurrentItem(0)\n        return true\n    end\n\n    mHits[1] = mHits[2]\n    mHits[2] = SystemClock.uptimeMillis();\n    if mHits[1] + 1500 < SystemClock.uptimeMillis() then\n        activity.toast(\"再按一次退出\");\n        return true\n    end\n    return false\nend"
  },
  {
    "path": "lua_main/md5.lua",
    "content": "local md5 = {\n    _VERSION = \"md5.lua 1.1.0\",\n    _DESCRIPTION = \"MD5 computation in Lua (5.1-3, LuaJIT)\",\n    _URL = \"https://github.com/kikito/md5.lua\",\n    _LICENSE = [[\n    MIT LICENSE\n    Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software\n    Permission is hereby granted, free of charge, to any person obtaining a\n    copy of this software and associated documentation files (the\n    \"Software\"), to deal in the Software without restriction, including\n    without limitation the rights to use, copy, modify, merge, publish,\n    distribute, sublicense, and/or sell copies of the Software, and to\n    permit persons to whom the Software is furnished to do so, subject to\n    the following conditions:\n    The above copyright notice and this permission notice shall be included\n    in all copies or substantial portions of the Software.\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n  ]]\n}\n\n-- bit lib implementions\n\nlocal char, byte, format, rep, sub =\nstring.char, string.byte, string.format, string.rep, string.sub\nlocal bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift\n\nlocal ok, bit = pcall(require, 'bit')\nif ok then\n    bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift = bit.bor, bit.band, bit.bnot, bit.bxor, bit.rshift, bit.lshift\nelse\n    ok, bit = pcall(require, 'bit32')\n\n    if ok then\n\n        bit_not = bit.bnot\n\n        local tobit = function(n)\n            return n <= 0x7fffffff and n or -(bit_not(n) + 1)\n        end\n\n        local normalize = function(f)\n            return function(a, b) return tobit(f(tobit(a), tobit(b))) end\n        end\n\n        bit_or, bit_and, bit_xor = normalize(bit.bor), normalize(bit.band), normalize(bit.bxor)\n        bit_rshift, bit_lshift = normalize(bit.rshift), normalize(bit.lshift)\n\n    else\n\n        local function tbl2number(tbl)\n            local result = 0\n            local power = 1\n            for i = 1, #tbl do\n                result = result + tbl[i] * power\n                power = power * 2\n            end\n            return result\n        end\n\n        local function expand(t1, t2)\n            local big, small = t1, t2\n            if (#big < #small) then\n                big, small = small, big\n            end\n            -- expand small\n            for i = #small + 1, #big do\n                small[i] = 0\n            end\n        end\n\n        local to_bits -- needs to be declared before bit_not\n\n        bit_not = function(n)\n            local tbl = to_bits(n)\n            local size = math.max(#tbl, 32)\n            for i = 1, size do\n                if (tbl[i] == 1) then\n                    tbl[i] = 0\n                else\n                    tbl[i] = 1\n                end\n            end\n            return tbl2number(tbl)\n        end\n\n        -- defined as local above\n        to_bits = function(n)\n            if (n < 0) then\n                -- negative\n                return to_bits(bit_not(math.abs(n)) + 1)\n            end\n            -- to bits table\n            local tbl = {}\n            local cnt = 1\n            local last\n            while n > 0 do\n                last = n % 2\n                tbl[cnt] = last\n                n = (n - last) / 2\n                cnt = cnt + 1\n            end\n\n            return tbl\n        end\n\n        bit_or = function(m, n)\n            local tbl_m = to_bits(m)\n            local tbl_n = to_bits(n)\n            expand(tbl_m, tbl_n)\n\n            local tbl = {}\n            for i = 1, #tbl_m do\n                if (tbl_m[i] == 0 and tbl_n[i] == 0) then\n                    tbl[i] = 0\n                else\n                    tbl[i] = 1\n                end\n            end\n\n            return tbl2number(tbl)\n        end\n\n        bit_and = function(m, n)\n            local tbl_m = to_bits(m)\n            local tbl_n = to_bits(n)\n            expand(tbl_m, tbl_n)\n\n            local tbl = {}\n            for i = 1, #tbl_m do\n                if (tbl_m[i] == 0 or tbl_n[i] == 0) then\n                    tbl[i] = 0\n                else\n                    tbl[i] = 1\n                end\n            end\n\n            return tbl2number(tbl)\n        end\n\n        bit_xor = function(m, n)\n            local tbl_m = to_bits(m)\n            local tbl_n = to_bits(n)\n            expand(tbl_m, tbl_n)\n\n            local tbl = {}\n            for i = 1, #tbl_m do\n                if (tbl_m[i] ~= tbl_n[i]) then\n                    tbl[i] = 1\n                else\n                    tbl[i] = 0\n                end\n            end\n\n            return tbl2number(tbl)\n        end\n\n        bit_rshift = function(n, bits)\n            local high_bit = 0\n            if (n < 0) then\n                -- negative\n                n = bit_not(math.abs(n)) + 1\n                high_bit = 0x80000000\n            end\n\n            local floor = math.floor\n\n            for i = 1, bits do\n                n = n / 2\n                n = bit_or(floor(n), high_bit)\n            end\n            return floor(n)\n        end\n\n        bit_lshift = function(n, bits)\n            if (n < 0) then\n                -- negative\n                n = bit_not(math.abs(n)) + 1\n            end\n\n            for i = 1, bits do\n                n = n * 2\n            end\n            return bit_and(n, 0xFFFFFFFF)\n        end\n    end\nend\n\n-- convert little-endian 32-bit int to a 4-char string\nlocal function lei2str(i)\n    local f = function(s) return char(bit_and(bit_rshift(i, s), 255)) end\n    return f(0) .. f(8) .. f(16) .. f(24)\nend\n\n-- convert raw string to big-endian int\nlocal function str2bei(s)\n    local v = 0\n    for i = 1, #s do\n        v = v * 256 + byte(s, i)\n    end\n    return v\nend\n\n-- convert raw string to little-endian int\nlocal function str2lei(s)\n    local v = 0\n    for i = #s, 1, -1 do\n        v = v * 256 + byte(s, i)\n    end\n    return v\nend\n\n-- cut up a string in little-endian ints of given size\nlocal function cut_le_str(s, ...)\n    local o, r = 1, {}\n    local args = { ... }\n    for i = 1, #args do\n        table.insert(r, str2lei(sub(s, o, o + args[i] - 1)))\n        o = o + args[i]\n    end\n    return r\nend\n\nlocal swap = function(w) return str2bei(lei2str(w)) end\n\n-- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh)\n-- 10/02/2001 jcw@equi4.com\n\nlocal CONSTS = {\n    0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,\n    0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,\n    0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,\n    0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,\n    0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,\n    0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,\n    0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,\n    0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,\n    0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,\n    0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,\n    0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,\n    0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,\n    0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,\n    0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,\n    0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,\n    0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,\n    0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476\n}\n\nlocal f = function(x, y, z) return bit_or(bit_and(x, y), bit_and(-x - 1, z)) end\nlocal g = function(x, y, z) return bit_or(bit_and(x, z), bit_and(y, -z - 1)) end\nlocal h = function(x, y, z) return bit_xor(x, bit_xor(y, z)) end\nlocal i = function(x, y, z) return bit_xor(y, bit_or(x, -z - 1)) end\nlocal z = function(ff, a, b, c, d, x, s, ac)\n    a = bit_and(a + ff(b, c, d) + x + ac, 0xFFFFFFFF)\n    -- be *very* careful that left shift does not cause rounding!\n    return bit_or(bit_lshift(bit_and(a, bit_rshift(0xFFFFFFFF, s)), s), bit_rshift(a, 32 - s)) + b\nend\n\nlocal function transform(A, B, C, D, X)\n    local a, b, c, d = A, B, C, D\n    local t = CONSTS\n\n    a = z(f, a, b, c, d, X[0], 7, t[1])\n    d = z(f, d, a, b, c, X[1], 12, t[2])\n    c = z(f, c, d, a, b, X[2], 17, t[3])\n    b = z(f, b, c, d, a, X[3], 22, t[4])\n    a = z(f, a, b, c, d, X[4], 7, t[5])\n    d = z(f, d, a, b, c, X[5], 12, t[6])\n    c = z(f, c, d, a, b, X[6], 17, t[7])\n    b = z(f, b, c, d, a, X[7], 22, t[8])\n    a = z(f, a, b, c, d, X[8], 7, t[9])\n    d = z(f, d, a, b, c, X[9], 12, t[10])\n    c = z(f, c, d, a, b, X[10], 17, t[11])\n    b = z(f, b, c, d, a, X[11], 22, t[12])\n    a = z(f, a, b, c, d, X[12], 7, t[13])\n    d = z(f, d, a, b, c, X[13], 12, t[14])\n    c = z(f, c, d, a, b, X[14], 17, t[15])\n    b = z(f, b, c, d, a, X[15], 22, t[16])\n\n    a = z(g, a, b, c, d, X[1], 5, t[17])\n    d = z(g, d, a, b, c, X[6], 9, t[18])\n    c = z(g, c, d, a, b, X[11], 14, t[19])\n    b = z(g, b, c, d, a, X[0], 20, t[20])\n    a = z(g, a, b, c, d, X[5], 5, t[21])\n    d = z(g, d, a, b, c, X[10], 9, t[22])\n    c = z(g, c, d, a, b, X[15], 14, t[23])\n    b = z(g, b, c, d, a, X[4], 20, t[24])\n    a = z(g, a, b, c, d, X[9], 5, t[25])\n    d = z(g, d, a, b, c, X[14], 9, t[26])\n    c = z(g, c, d, a, b, X[3], 14, t[27])\n    b = z(g, b, c, d, a, X[8], 20, t[28])\n    a = z(g, a, b, c, d, X[13], 5, t[29])\n    d = z(g, d, a, b, c, X[2], 9, t[30])\n    c = z(g, c, d, a, b, X[7], 14, t[31])\n    b = z(g, b, c, d, a, X[12], 20, t[32])\n\n    a = z(h, a, b, c, d, X[5], 4, t[33])\n    d = z(h, d, a, b, c, X[8], 11, t[34])\n    c = z(h, c, d, a, b, X[11], 16, t[35])\n    b = z(h, b, c, d, a, X[14], 23, t[36])\n    a = z(h, a, b, c, d, X[1], 4, t[37])\n    d = z(h, d, a, b, c, X[4], 11, t[38])\n    c = z(h, c, d, a, b, X[7], 16, t[39])\n    b = z(h, b, c, d, a, X[10], 23, t[40])\n    a = z(h, a, b, c, d, X[13], 4, t[41])\n    d = z(h, d, a, b, c, X[0], 11, t[42])\n    c = z(h, c, d, a, b, X[3], 16, t[43])\n    b = z(h, b, c, d, a, X[6], 23, t[44])\n    a = z(h, a, b, c, d, X[9], 4, t[45])\n    d = z(h, d, a, b, c, X[12], 11, t[46])\n    c = z(h, c, d, a, b, X[15], 16, t[47])\n    b = z(h, b, c, d, a, X[2], 23, t[48])\n\n    a = z(i, a, b, c, d, X[0], 6, t[49])\n    d = z(i, d, a, b, c, X[7], 10, t[50])\n    c = z(i, c, d, a, b, X[14], 15, t[51])\n    b = z(i, b, c, d, a, X[5], 21, t[52])\n    a = z(i, a, b, c, d, X[12], 6, t[53])\n    d = z(i, d, a, b, c, X[3], 10, t[54])\n    c = z(i, c, d, a, b, X[10], 15, t[55])\n    b = z(i, b, c, d, a, X[1], 21, t[56])\n    a = z(i, a, b, c, d, X[8], 6, t[57])\n    d = z(i, d, a, b, c, X[15], 10, t[58])\n    c = z(i, c, d, a, b, X[6], 15, t[59])\n    b = z(i, b, c, d, a, X[13], 21, t[60])\n    a = z(i, a, b, c, d, X[4], 6, t[61])\n    d = z(i, d, a, b, c, X[11], 10, t[62])\n    c = z(i, c, d, a, b, X[2], 15, t[63])\n    b = z(i, b, c, d, a, X[9], 21, t[64])\n\n    return bit_and(A + a, 0xFFFFFFFF), bit_and(B + b, 0xFFFFFFFF),\n    bit_and(C + c, 0xFFFFFFFF), bit_and(D + d, 0xFFFFFFFF)\nend\n\n----------------------------------------------------------------\nlocal function md5_update(self, s)\n    self.pos = self.pos + #s\n    s = self.buf .. s\n    for ii = 1, #s - 63, 64 do\n        local X = cut_le_str(sub(s, ii, ii + 63), 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4)\n        assert(#X == 16)\n        X[0] = table.remove(X, 1) -- zero based!\n        self.a, self.b, self.c, self.d = transform(self.a, self.b, self.c, self.d, X)\n    end\n    self.buf = sub(s, math.floor(#s / 64) * 64 + 1, #s)\n    return self\nend\n\nlocal function md5_finish(self)\n    local msgLen = self.pos\n    local padLen = 56 - msgLen % 64\n\n    if msgLen % 64 > 56 then padLen = padLen + 64 end\n\n    if padLen == 0 then padLen = 64 end\n\n    local s = char(128) .. rep(char(0), padLen - 1) .. lei2str(bit_and(8 * msgLen, 0xFFFFFFFF)) .. lei2str(math.floor(msgLen / 0x20000000))\n    md5_update(self, s)\n\n    assert(self.pos % 64 == 0)\n    return lei2str(self.a) .. lei2str(self.b) .. lei2str(self.c) .. lei2str(self.d)\nend\n\n----------------------------------------------------------------\nfunction md5.new()\n    return {\n        a = CONSTS[65],\n        b = CONSTS[66],\n        c = CONSTS[67],\n        d = CONSTS[68],\n        pos = 0,\n        buf = '',\n        update = md5_update,\n        finish = md5_finish\n    }\nend\n\nfunction md5.tohex(s)\n    return format(\"%08x%08x%08x%08x\", str2bei(sub(s, 1, 4)), str2bei(sub(s, 5, 8)), str2bei(sub(s, 9, 12)), str2bei(sub(s, 13, 16)))\nend\n\nfunction md5.sum(s)\n    return md5.new():update(s):finish()\nend\n\nfunction md5.sumhexa(s)\n    return md5.tohex(md5.sum(s))\nend\n\nreturn md5"
  },
  {
    "path": "lua_main/uihelper.lua",
    "content": "local uihelper = {}\n\nlocal function runOnUiThread(activity, f)\n    activity.runOnUiThread(luajava.createProxy('java.lang.Runnable', {\n        run = f\n    }))\nend\n\nlocal density\nlocal screenWidth\n\nlocal function dp2px(dp)\n    if density == nil then\n        import \"androlua.LuaUtil\"\n        density = LuaUtil.getDensity()\n        screenWidth = LuaUtil.getScreenWidth()\n    end\n    return 0.5 + dp * density\nend\n\nlocal function getScreenWidth()\n    if screenWidth == nil then\n        dp2px(0)\n    end\n    return screenWidth\nend\n\nuihelper.runOnUiThread = runOnUiThread\nuihelper.dp2px = dp2px\nuihelper.getScreenWidth = getScreenWidth\n\nreturn uihelper\n\n"
  },
  {
    "path": "sample/.gitignore",
    "content": "/build\n/release/\n"
  },
  {
    "path": "sample/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 28\n\n    defaultConfig {\n        applicationId \"pub.hydrogen.android\"\n        minSdkVersion 16\n        targetSdkVersion 28\n        versionCode 28\n        versionName \"1.2.1\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    signingConfigs {\n        release {\n            Properties properties = new Properties()\n            properties.load(project.rootProject.file('local.properties').newDataInputStream())\n            storeFile file(properties.getProperty('KEYSTORE_DIR', null))\n            storePassword properties.getProperty('KESTORE_PASSWORD', null)\n            keyAlias properties.getProperty('KEY_ALIAS', null)\n            keyPassword properties.getProperty('KEY_PASSWORD', null)\n        }\n\n    }\n    buildTypes {\n        debug {\n            debuggable true\n            signingConfig signingConfigs.release\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n        release {\n            minifyEnabled true\n            zipAlignEnabled true\n            signingConfig signingConfigs.release\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n        preRelease {\n            debuggable true\n            minifyEnabled true\n            zipAlignEnabled true\n            signingConfig signingConfigs.release\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    implementation fileTree(include: ['*.jar'], dir: 'libs')\n    androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {\n        exclude group: 'com.android.support', module: 'support-annotations'\n    })\n    implementation project(':hydrogen-library')\n    implementation 'com.android.support:appcompat-v7:28.0.0'\n    implementation 'com.android.support:design:28.0.0'\n    implementation 'com.tencent.bugly:crashreport_upgrade:1.3.5'\n    testImplementation 'junit:junit:4.12'\n}\n"
  },
  {
    "path": "sample/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:\\android-sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n-dontwarn com.tencent.bugly.**\n-keep public class com.tencent.bugly.**{*;}\n\n-keep class android.**{*;}\n-keep class androlua.**{*;}\n-keep class com.**{*;}\n-keep class androlua.common.**{*;}\n-keep class pub.**{*;}\n-keep class pub.**{*;}\n# Glide\n-keep public class * implements com.bumptech.glide.module.GlideModule\n-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {\n  **[] $VALUES;\n  public *;\n}\n\n# Okhttp\n-dontwarn okio.**\n-dontwarn javax.annotation.Nullable\n-dontwarn javax.annotation.ParametersAreNonnullByDefault\n\n-keep  class okio.**{*;}\n-keep  class okhttp3.**{*;}\n\n# JSR 305 annotations are for embedding nullability information.\n-dontwarn javax.annotation.**\n\n# A resource is loaded with a relative path so the package of this class must be preserved.\n-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase\n\n# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.\n-dontwarn org.codehaus.mojo.animal_sniffer.*\n\n# OkHttp platform used only on JVM and when Conscrypt dependency is available.\n-dontwarn okhttp3.internal.platform.ConscryptPlatform\n\n-keep  class cn.jzvd.**{*;}"
  },
  {
    "path": "sample/src/androidTest/java/pub/hanks/sample/ExampleInstrumentedTest.java",
    "content": "package pub.hanks.sample;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\nimport android.widget.TextView;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumentation test, which will execute on an Android device.\n *\n * @see <byteToString href=\"http://d.android.com/tools/testing\">Testing documentation</byteToString>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"pub.hanks.sample\", appContext.getPackageName());\n        TextView textView = new TextView(appContext);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n            textView.setLineSpacing(textView.getLineSpacingExtra(),textView.getLineSpacingMultiplier());\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"pub.hydrogen.android\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n\n    <uses-permission android:name=\"com.android.launcher.permission.INSTALL_SHORTCUT\" />\n    <uses-permission android:name=\"com.android.launcher.permission.CREATE_SHORTCUT\" />\n    <uses-permission android:name=\"com.android.launcher.permission.UNINSTALL_SHORTCUT\" />\n    <application\n        android:name=\"pub.hanks.sample.App\"\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\"pub.hanks.sample.SplashActivity\"\n            android:theme=\"@style/SplashTheme\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "sample/src/main/java/pub/hanks/sample/App.java",
    "content": "package pub.hanks.sample;\n\nimport android.app.Application;\nimport com.tencent.bugly.Bugly;\nimport com.tencent.bugly.beta.Beta;\n\nimport androlua.LuaManager;\nimport pub.hydrogen.android.R;\n\n/**\n * Created by hanks on 2017/5/16. Copyright (C) 2017 Hanks\n */\n\npublic class App extends Application {\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        LuaManager.getInstance().init(this);\n        initBugly();\n    }\n\n    public void initBugly() {\n        Beta.upgradeDialogLayoutId = R.layout.upgrade_dialog;\n        Bugly.init(getApplicationContext(), \"4bd5f2ea3e\", false);\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/pub/hanks/sample/ITHomeUtils.java",
    "content": "package pub.hanks.sample;\n\nimport java.security.Key;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.spec.SecretKeySpec;\n\n/**\n * Created by hanks on 2017/5/27. Copyright (C) 2017 Hanks\n */\n\npublic class ITHomeUtils {\n\n    public static String byteToString(byte[] bArr) {\n        StringBuffer stringBuffer = new StringBuffer();\n        for (byte b : bArr) {\n            String toHexString = Integer.toHexString(b & 255);\n            System.out.println(b + \",\" + toHexString);\n            if (toHexString.length() == 1) {\n                stringBuffer.append(\"0\" + toHexString);\n            } else {\n                stringBuffer.append(toHexString);\n            }\n        }\n        return stringBuffer.toString();\n    }\n\n    public static String desEncode(String id) throws Exception {\n        Key secretKeySpec = new SecretKeySpec(\"p#a@w^s(\".getBytes(), \"DES\");\n        Cipher instance = Cipher.getInstance(\"DES/ECB/NoPadding\");\n        instance.init(1, secretKeySpec);\n        int length = id.length();\n        // 补充为 8 个\n        if (length < 8) {\n            length = 8 - length;\n        } else {\n            length %= 8;\n            if (length != 0) {\n                length = 8 - length;\n            } else {\n                length = 0;\n            }\n        }\n        int i = 0;\n        while (i < length) {\n            id = id + \"\\u0000\";\n            i++;\n        }\n        return byteToString(instance.doFinal(id.getBytes()));\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/pub/hanks/sample/SplashActivity.java",
    "content": "package pub.hanks.sample;\n\nimport android.Manifest;\nimport android.content.ContentUris;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.graphics.Color;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.provider.DocumentsContract;\nimport android.provider.MediaStore;\nimport android.support.annotation.NonNull;\nimport android.support.v4.app.ActivityCompat;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport org.json.JSONObject;\n\nimport java.util.Calendar;\nimport java.util.Locale;\n\nimport androlua.LuaActivity;\nimport androlua.LuaImageLoader;\nimport androlua.LuaManager;\nimport androlua.base.BaseActivity;\nimport androlua.common.LuaConstants;\nimport androlua.common.LuaFileUtils;\nimport androlua.common.LuaSp;\nimport androlua.common.LuaStringUtils;\nimport pub.hydrogen.android.BuildConfig;\nimport pub.hydrogen.android.R;\n\nimport static android.content.pm.PackageManager.PERMISSION_GRANTED;\n\npublic class SplashActivity extends BaseActivity {\n    public static final String FILE_SP = \"pub_hanks_sample\";\n    private ImageView iv_bg;\n    private TextView tv_author, tv_day, tv_date, tv_text, tv_default;\n    private View layout_default, layer;\n    private LuaSp sp;\n\n    public static void getOpenView(Context context, int type, Object iAdSuccessBack) {\n\n    }\n\n    public static void getOpenNativeView(Context context, int type, Object iAdSuccessBack) {\n\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        View decorView = getWindow().getDecorView();\n        int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN\n                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;\n        decorView.setSystemUiVisibility(option);\n\n        setStatusBarColor(Color.TRANSPARENT);\n        setContentView(R.layout.activity_splash);\n        iv_bg = (ImageView) findViewById(R.id.iv_bg);\n        tv_author = (TextView) findViewById(R.id.tv_author);\n        tv_text = (TextView) findViewById(R.id.tv_text);\n        tv_date = (TextView) findViewById(R.id.tv_date);\n        tv_day = (TextView) findViewById(R.id.tv_day);\n        tv_default = (TextView) findViewById(R.id.tv_default);\n        layout_default = findViewById(R.id.layer_defalut);\n        layer = findViewById(R.id.layer);\n\n        final ViewGroup layout_ad = (ViewGroup) findViewById(R.id.layout_ad);\n        sp = LuaSp.getInstance(\"luandroid\");\n        initContent();\n        initFiles();\n        if (ActivityCompat.checkSelfPermission(this,\n                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PERMISSION_GRANTED\n                || ActivityCompat.checkSelfPermission(this,\n                Manifest.permission.READ_EXTERNAL_STORAGE) != PERMISSION_GRANTED) {\n            ActivityCompat.requestPermissions(this, new String[]{\n                    Manifest.permission.WRITE_EXTERNAL_STORAGE,\n                    Manifest.permission.READ_EXTERNAL_STORAGE\n            }, 0x233);\n        } else {\n            launch();\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        if (requestCode == 0x233) {\n            if (ActivityCompat.checkSelfPermission(this,\n                    Manifest.permission.WRITE_EXTERNAL_STORAGE) == PERMISSION_GRANTED\n                    || ActivityCompat.checkSelfPermission(this,\n                    Manifest.permission.READ_EXTERNAL_STORAGE) == PERMISSION_GRANTED) {\n                launch();\n            } else {\n                ActivityCompat.requestPermissions(this, new String[]{\n                        Manifest.permission.WRITE_EXTERNAL_STORAGE,\n                        Manifest.permission.READ_EXTERNAL_STORAGE\n                }, 0x233);\n            }\n        }\n    }\n\n\n    private void launch() {\n        tv_day.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                launchMain();\n            }\n        }, 2000);\n    }\n\n    private void initContent() {\n        try {\n            Calendar calendar = Calendar.getInstance(Locale.getDefault());\n            tv_day.setText(String.format(Locale.getDefault(), \"%d\", calendar.get(Calendar.DAY_OF_MONTH)));\n            String week = getWeekStr(calendar.get(Calendar.DAY_OF_WEEK) - 1);\n            tv_date.setText(String.format(Locale.getDefault(), \"/ %d月  星期%s\",\n                    calendar.get(Calendar.MONTH) + 1, week));\n            tv_default.setText(String.format(Locale.getDefault(), \"%d年%d月%d日，星期%s\\n遇见你，真好\",\n                    calendar.get(Calendar.YEAR),\n                    calendar.get(Calendar.MONTH) + 1,\n                    calendar.get(Calendar.DAY_OF_MONTH),\n                    week));\n            String splash = sp.get(\"splash\", \"\");\n            String config = LuaSp.getInstance(\"luandroid\").get(\"config\", \"\");\n\n            boolean customSplash = false;\n            if (!LuaStringUtils.isEmpty(config)) {\n                JSONObject configJson = new JSONObject(config);\n                if (configJson.has(\"home_splash\")) {\n                    String home_splash = configJson.getString(\"home_splash\");\n                    if (home_splash != null) {\n                        Log.e(\"==============\", \"initContent: \" + home_splash);\n                        LuaImageLoader.load(iv_bg, handleImageOnKitKat(Uri.parse(home_splash)));\n                        layer.setVisibility(View.VISIBLE);\n                        customSplash = true;\n                    }\n                }\n            }\n            if (!LuaStringUtils.isEmpty(splash)) {\n                JSONObject json = new JSONObject(splash);\n                tv_text.setText(json.getString(\"text\"));\n                tv_author.setText(json.getString(\"from\"));\n                if (!customSplash) {\n                    LuaImageLoader.load(iv_bg, json.getString(\"img\"));\n                    layer.setVisibility(View.VISIBLE);\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    private String getImagePath(Uri uri, String selection) {\n        String path = null;\n        Cursor cursor = getContentResolver().query(uri, null, selection, null, null);\n        if (cursor != null) {\n            if (cursor.moveToFirst()) {\n                path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));\n            }\n            cursor.close();\n        }\n        return path;\n    }\n\n    private String handleImageOnKitKat(Uri uri) {\n        String imagePath = null;\n        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {\n            return uri.toString();\n        }\n        if (DocumentsContract.isDocumentUri(this, uri)) {\n            String docId = DocumentsContract.getDocumentId(uri);\n            if (\"com.android.providers.media.documents\".equals(uri.getAuthority())) {\n                String id = docId.split(\":\")[1];\n                String selection = MediaStore.Images.Media._ID + \"=\" + id;\n                imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);\n            } else if (\"com.android.providers.downloads.documents\".equals(uri.getAuthority())) {\n                Uri contentUri = ContentUris.withAppendedId(\n                        Uri.parse(\"content://downloads/public_downloads\"),\n                        Long.valueOf(docId));\n                imagePath = getImagePath(contentUri, null);\n            }\n        } else if (\"content\".equalsIgnoreCase(uri.getScheme())) {\n            imagePath = getImagePath(uri, null);\n        }\n        return imagePath;\n    }\n\n\n    private String getWeekStr(int week_index) {\n        String[] weeks = {\"日\", \"一\", \"二\", \"三\", \"四\", \"五\", \"六\"};\n        if (week_index < 0) {\n            week_index = 0;\n        }\n        return weeks[week_index];\n    }\n\n    private void initFiles() {\n        new Thread() {\n            @Override\n            public void run() {\n                super.run();\n                LuaFileUtils.copyAssetsFlies(\"lua\", LuaManager.getInstance().getLuaDir());\n                LuaSp.getInstance(FILE_SP).save(LuaConstants.KEY_VERSION, BuildConfig.VERSION_CODE);\n            }\n        }.start();\n    }\n\n    public void launchMain() {\n        Intent intent = new Intent(this, LuaActivity.class);\n        intent.putExtra(\"luaPath\", LuaManager.getInstance().getLuaDir() + \"/main.lua\");\n//        intent.putExtra(\"luaPath\", LuaManager.getInstance().getLuaExtDir() + \"/main.lua\");\n        startActivity(intent);\n        tv_day.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                finish();\n            }\n        }, 2000);\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/pub/hanks/sample/adapter/DragTouchHelper.java",
    "content": "package pub.hanks.sample.adapter;\n\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.helper.ItemTouchHelper;\n\n/**\n * Created by hanks on 2017/7/13.\n */\n\npublic class DragTouchHelper extends ItemTouchHelper.Callback {\n\n    private Creator creator;\n\n    public DragTouchHelper(Creator creator) {\n        this.creator = creator;\n    }\n\n    @Override\n    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {\n        int dragFlags = 0;\n        int swipeFlags = 0;\n        if (creator != null) {\n            dragFlags = (int) creator.getDragFlags();\n            swipeFlags = (int) creator.getSwipeFlags();\n        }\n        return makeMovementFlags(dragFlags, swipeFlags);\n    }\n\n    @Override\n    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {\n        if (creator != null) {\n            return creator.onMove(recyclerView, viewHolder, target);\n        }\n        return false;\n\n    }\n\n    @Override\n    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {\n        if (creator != null) {\n            creator.onSwiped(viewHolder, direction);\n        }\n\n    }\n\n    @Override\n    public boolean isLongPressDragEnabled() {\n        if (creator != null) {\n            return creator.isLongPressDragEnabled();\n        }\n        return super.isLongPressDragEnabled();\n    }\n\n    @Override\n    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {\n        if (creator != null) {\n            creator.onSelectedChanged(viewHolder, actionState);\n        }\n        super.onSelectedChanged(viewHolder, actionState);\n    }\n\n    @Override\n    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {\n        if (creator != null) {\n            creator.clearView(recyclerView, viewHolder);\n        }\n        super.clearView(recyclerView, viewHolder);\n    }\n\n    public interface Creator {\n        boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target);\n\n        void onSwiped(RecyclerView.ViewHolder viewHolder, int direction);\n\n        void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState);\n\n        void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder);\n\n        long getDragFlags();\n\n        long getSwipeFlags();\n\n        boolean isLongPressDragEnabled();\n    }\n}\n"
  },
  {
    "path": "sample/src/main/res/anim/slide_in_from_bottom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2015 The Android Open Source Project\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~      http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n-->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:duration=\"@android:integer/config_shortAnimTime\"\n    android:interpolator=\"@android:anim/accelerate_decelerate_interpolator\">\n\n    <translate\n        android:fromYDelta=\"20%p\"\n        android:toYDelta=\"0\"/>\n\n    <alpha\n        android:fromAlpha=\"0.0\"\n        android:toAlpha=\"1.0\"/>\n\n</set>\n"
  },
  {
    "path": "sample/src/main/res/anim/slide_in_right.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n/* //device/apps/common/res/anim/slide_in_right.xml\n**\n** Copyright 2007, The Android Open Source Project\n**\n** Licensed under the Apache License, Version 2.0 (the \"License\"); \n** you may not use this file except in compliance with the License. \n** You may obtain a copy of the License at \n**\n**     http://www.apache.org/licenses/LICENSE-2.0 \n**\n** Unless required by applicable law or agreed to in writing, software \n** distributed under the License is distributed on an \"AS IS\" BASIS, \n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n** See the License for the specific language governing permissions and \n** limitations under the License.\n*/\n-->\n\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:duration=\"@android:integer/config_shortAnimTime\"\n    android:interpolator=\"@android:anim/decelerate_interpolator\">\n    <translate\n        android:fromXDelta=\"100%p\"\n        android:toXDelta=\"0\" />\n</set>\n"
  },
  {
    "path": "sample/src/main/res/anim/slide_out_from_bottom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ Copyright (C) 2015 The Android Open Source Project\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~      http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n-->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:duration=\"@android:integer/config_shortAnimTime\"\n    android:interpolator=\"@android:anim/accelerate_decelerate_interpolator\">\n\n    <translate\n        android:fromYDelta=\"0\"\n        android:toYDelta=\"20%p\" />\n\n    <alpha\n        android:fromAlpha=\"1.0\"\n        android:toAlpha=\"0.0\" />\n\n</set>\n"
  },
  {
    "path": "sample/src/main/res/anim/slide_out_left.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n/* //device/apps/common/res/anim/slide_out_left.xml\n**\n** Copyright 2007, The Android Open Source Project\n**\n** Licensed under the Apache License, Version 2.0 (the \"License\"); \n** you may not use this file except in compliance with the License. \n** You may obtain a copy of the License at \n**\n**     http://www.apache.org/licenses/LICENSE-2.0 \n**\n** Unless required by applicable law or agreed to in writing, software \n** distributed under the License is distributed on an \"AS IS\" BASIS, \n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n** See the License for the specific language governing permissions and \n** limitations under the License.\n*/\n-->\n\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t<translate android:fromXDelta=\"0\" android:toXDelta=\"-80%p\"\n            android:duration=\"@android:integer/config_mediumAnimTime\"/>\n</set>\n"
  },
  {
    "path": "sample/src/main/res/anim/slide_out_right.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n/* //device/apps/common/res/anim/slide_in_right.xml\n**\n** Copyright 2007, The Android Open Source Project\n**\n** Licensed under the Apache License, Version 2.0 (the \"License\"); \n** you may not use this file except in compliance with the License. \n** You may obtain a copy of the License at \n**\n**     http://www.apache.org/licenses/LICENSE-2.0 \n**\n** Unless required by applicable law or agreed to in writing, software \n** distributed under the License is distributed on an \"AS IS\" BASIS, \n** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n** See the License for the specific language governing permissions and \n** limitations under the License.\n*/\n-->\n\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:duration=\"@android:integer/config_shortAnimTime\"\n    android:interpolator=\"@android:anim/accelerate_decelerate_interpolator\">\n    <translate\n        android:fromXDelta=\"0\"\n        android:toXDelta=\"100%p\" />\n</set>\n"
  },
  {
    "path": "sample/src/main/res/drawable/shadow_splash.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <gradient\n        android:angle=\"90\"\n        android:endColor=\"#00000000\"\n        android:startColor=\"#88000000\"\n        android:type=\"linear\" />\n</shape>"
  },
  {
    "path": "sample/src/main/res/layout/activity_splash.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"pub.hanks.sample.SplashActivity\">\n\n    <FrameLayout\n        android:id=\"@+id/layer_defalut\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <ImageView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:layout_marginTop=\"100dp\"\n            android:src=\"@drawable/smile\"\n            android:tint=\"#9c9c9c\" />\n\n        <TextView\n            android:id=\"@+id/tv_default\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"200dp\"\n            android:gravity=\"center\"\n            android:lineSpacingMultiplier=\"1.3\"\n            android:text=\"2018年5月13日，星期三\\n遇见你，真好\"\n            android:textColor=\"#9c9c9c\"\n            android:textSize=\"16sp\" />\n\n        <ImageView\n            android:layout_width=\"50dp\"\n            android:layout_height=\"50dp\"\n            android:layout_gravity=\"center_horizontal|bottom\"\n            android:layout_marginBottom=\"70dp\"\n            android:alpha=\"0.9\"\n            android:src=\"@drawable/logo_no_bg\" />\n    </FrameLayout>\n\n    <ImageView\n        android:id=\"@+id/iv_bg\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"centerCrop\" />\n\n    <LinearLayout\n        android:id=\"@+id/layer\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:background=\"@drawable/shadow_splash\"\n        android:orientation=\"vertical\"\n        android:paddingBottom=\"40dp\"\n        android:paddingLeft=\"20dp\"\n        android:paddingRight=\"20dp\"\n        android:paddingTop=\"120dp\"\n        android:visibility=\"gone\">\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"20dp\"\n            android:orientation=\"horizontal\"\n            android:paddingRight=\"2dp\">\n\n            <TextView\n                android:id=\"@+id/tv_day\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_toLeftOf=\"@+id/tv_date\"\n                android:text=\"14 \"\n                android:textColor=\"#FFFFFF\"\n                android:textSize=\"32sp\" />\n\n            <TextView\n                android:id=\"@+id/tv_date\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignBaseline=\"@+id/tv_day\"\n                android:layout_alignParentRight=\"true\"\n                android:layout_marginLeft=\"2dp\"\n                android:text=\"/ 2月   星期五\"\n                android:textColor=\"#FFFFFF\"\n                android:textSize=\"13sp\" />\n        </RelativeLayout>\n\n        <TextView\n            android:id=\"@+id/tv_text\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_above=\"@+id/tv_author\"\n            android:gravity=\"right\"\n            android:lineSpacingMultiplier=\"1.5\"\n            android:text=\"有的时候，人们之所以哭泣并不他们坚强了太久\"\n            android:textColor=\"#F1FFFFFF\"\n            android:textSize=\"13sp\" />\n\n        <TextView\n            android:id=\"@+id/tv_author\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"16dp\"\n            android:alpha=\"0.9\"\n            android:gravity=\"right\"\n            android:text=\"太宰治（だざいおさむ）\"\n            android:textColor=\"#ffffff\"\n            android:textSize=\"12sp\"\n            android:visibility=\"gone\" />\n    </LinearLayout>\n\n    <FrameLayout\n        android:id=\"@+id/layout_ad\"\n        android:layout_width=\"100dp\"\n        android:layout_height=\"100dp\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_marginTop=\"40dp\" />\n</RelativeLayout>\n"
  },
  {
    "path": "sample/src/main/res/layout/upgrade_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                xmlns:tools=\"http://schemas.android.com/tools\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:background=\"#88000000\"\n                android:gravity=\"center\">\n\n    <LinearLayout\n        android:layout_width=\"280dp\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"#ffffff\"\n        android:gravity=\"center\"\n        android:orientation=\"vertical\">\n\n        <!-- 【必设】升级标题控件tag：beta_title-->\n        <TextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"20dp\"\n            android:layout_marginLeft=\"24dp\"\n            android:layout_marginRight=\"24dp\"\n            android:layout_marginTop=\"24dp\"\n            android:ellipsize=\"end\"\n            android:maxLines=\"2\"\n            android:tag=\"beta_title\"\n            android:text=\"发现新版本\"\n            android:textColor=\"#2b2b2b\"\n            android:textSize=\"18sp\"\n            android:textStyle=\"bold\"/>\n\n        <ScrollView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\"\n                android:paddingLeft=\"24dp\"\n                android:paddingRight=\"24dp\"\n                >\n                <!-- 【必设】升级信息控件tag：beta_upgrade_info-->\n                <TextView\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:lineSpacingMultiplier=\"1.3\"\n                    android:tag=\"beta_upgrade_info\"\n                    android:textColor=\"#757575\"\n                    android:textSize=\"14sp\"\n                    tools:text=\"版本:1.3.4大小:2M\"/>\n\n                <!-- 【必设】更新属性控件tag：beta_upgrade_feature-->\n                <TextView\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"4dp\"\n                    android:lineSpacingMultiplier=\"1.3\"\n                    android:tag=\"beta_upgrade_feature\"\n                    android:text=\"Side-by-side buttons Side-by-side but tonsSide-by-side buttonsSide-by-side buttons\"\n                    android:textColor=\"#535353\"\n                    android:textSize=\"14sp\"/>\n            </LinearLayout>\n        </ScrollView>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"52dp\"\n            android:layout_marginBottom=\"8dp\"\n            android:layout_marginTop=\"16dp\"\n            android:gravity=\"right|center_vertical\"\n            android:orientation=\"horizontal\">\n            <!-- 【必设】取消按钮tag：beta_cancel_button-->\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"36dp\"\n                android:layout_marginRight=\"8dp\"\n                android:background=\"@drawable/layout_selector_tran\"\n                android:ellipsize=\"end\"\n                android:gravity=\"center\"\n                android:maxLines=\"1\"\n                android:paddingLeft=\"10dp\"\n                android:paddingRight=\"10dp\"\n                android:tag=\"beta_cancel_button\"\n                android:text=\"下次再说\"\n                android:textColor=\"#757575\"\n                android:textSize=\"16sp\"/>\n            <!-- 【必设】确认按钮tag：beta_confirm_button-->\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"36dp\"\n                android:layout_marginRight=\"16dp\"\n                android:background=\"@drawable/layout_selector_tran\"\n                android:ellipsize=\"end\"\n                android:gravity=\"center\"\n                android:maxLines=\"1\"\n                android:paddingLeft=\"10dp\"\n                android:paddingRight=\"10dp\"\n                android:tag=\"beta_confirm_button\"\n                android:text=\"马上更新\"\n                android:textColor=\"#2b2b2b\"\n                android:textSize=\"16sp\"\n                android:textStyle=\"bold\"/>\n        </LinearLayout>\n\n    </LinearLayout>\n</RelativeLayout>"
  },
  {
    "path": "sample/src/main/res/raw/keep.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:keep=\"@drawable/*,@drawable-xxhdpi/*,@drawable-xxxhdpi/*\"/>"
  },
  {
    "path": "sample/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#2979FB</color>\n    <color name=\"colorPrimaryDark\">#2a70e2</color>\n    <color name=\"colorAccent\">#2979FB</color>\n    <color name=\"white\">#FFFFFF</color>\n    <color name=\"black\">#000000</color>\n    <color name=\"transparent\">#00FFFFFF</color>\n</resources>\n"
  },
  {
    "path": "sample/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">氢应用</string>\n</resources>\n"
  },
  {
    "path": "sample/src/main/res/values/styles.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowAnimationStyle\">@style/ActivityAnimation</item>\n    </style>\n\n\n    <style name=\"SplashTheme\" parent=\"AppTheme\">\n        <item name=\"colorPrimary\">@color/white</item>\n        <item name=\"colorPrimaryDark\">@color/white</item>\n        <item name=\"colorAccent\">@color/white</item>\n    </style>\n\n    <style name=\"ActivityAnimation\" parent=\"@style/Animation.Design.BottomSheetDialog\">\n        <item name=\"android:windowEnterAnimation\">@anim/slide_in_right</item>\n        <item name=\"android:windowExitAnimation\">@anim/slide_out_right</item>\n        <item name=\"android:windowShowAnimation\">@null</item>\n        <item name=\"android:windowHideAnimation\">@null</item>\n        <item name=\"android:windowEnterTransition\" tools:targetApi=\"lollipop\">@null</item>\n        <item name=\"android:windowExitTransition\" tools:targetApi=\"lollipop\">@null</item>\n    </style>\n\n    <style name=\"AppActivityAnim\" parent=\"@android:style/Animation.Activity\">\n        <item name=\"android:windowEnterAnimation\">@anim/slide_in_right</item>\n        <item name=\"android:windowExitAnimation\">@anim/slide_out_left</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "sample/src/test/java/pub/hanks/sample/ExampleUnitTest.java",
    "content": "package pub.hanks.sample;\n\nimport org.junit.Test;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\nimport androlua.common.LuaFileUtils;\n\nimport static java.util.zip.Deflater.BEST_COMPRESSION;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <byteToString href=\"http://d.android.com/tools/testing\">Testing documentation</byteToString>\n */\npublic class ExampleUnitTest {\n\n    class A{\n        \n    }\n    \n    class Aa extends A{\n        \n    }\n    @Test\n    public void testRun(){\n        A a = new Aa();\n        System.out.println(\"a.getClass() = \" + a.getClass());\n    }\n\n    public static void execCMD(String command) {\n        try {\n            Process child = Runtime.getRuntime().exec(command);\n            InputStreamReader isr = new InputStreamReader(child.getInputStream());\n            BufferedReader buff = new BufferedReader(isr);\n\n            String line;\n            while ((line = buff.readLine()) != null)\n                System.out.print(line);\n\n            InputStreamReader is2 = new InputStreamReader(child.getErrorStream());\n            BufferedReader buff2 = new BufferedReader(is2);\n\n            String line2;\n            while ((line2 = buff2.readLine()) != null)\n                System.out.println(line2);\n\n\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void zip(ZipOutputStream zOut, File file, String base) {\n        try {\n\n            // 如果文件句柄是目录\n            if (file.isDirectory()) {\n                //获取目录下的文件\n                File[] listFiles = file.listFiles();\n                // 建立ZIP条目\n                zOut.putNextEntry(new ZipEntry(base + \"/\"));\n                base = (base.length() == 0 ? \"\" : base + \"/\");\n                // 遍历目录下文件\n                for (int i = 0; i < listFiles.length; i++) {\n                    // 递归进入本方法\n                    zip(zOut, listFiles[i], base + listFiles[i].getName());\n                }\n            }\n            // 如果文件句柄是文件\n            else {\n                if (\"\".equals(base)) {\n                    base = file.getName();\n                }\n                // 填入文件句柄\n                zOut.putNextEntry(new ZipEntry(base));\n                // 开始压缩\n                // 从文件入流读,写入ZIP 出流\n                writeFile(zOut, file);\n            }\n\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n    }\n\n    public static void writeFile(ZipOutputStream zOut, File file) throws IOException {\n        FileInputStream in = new FileInputStream(file);\n        int len;\n        while ((len = in.read()) != -1)\n            zOut.write(len);\n        in.close();\n    }\n\n    @Test\n    public void addition_isCorrect() throws Exception {\n        LuaFileUtils.unzip(\"D:\\\\Desktop\\\\91pic-o.zip\", \"D:\\\\Desktop\");\n    }\n\n    @Test\n    public void unZipPlugin() throws Exception {\n        String zipDir = \"D:\\\\work\\\\opensource\\\\api_luanroid\\\\plugin\\\\eyepetizer.zip\";\n        LuaFileUtils.unzip(zipDir, \"D:\\\\Desktop\");\n    }\n\n    @Test\n    public void testCommand() throws Exception {\n        String command = \"node D:\\\\work\\\\opensource\\\\LuaJAndroid\\\\script\\\\node\\\\watch\\\\update_plugin_info.js\";\n        execCMD(command);\n    }\n\n    // 执行生成插件压缩文件\n    @Test\n    public void zipPlugin() throws Exception {\n\n        String compileLua = \"nodejs /home/hanks/work/opensource/LuaJAndroid/script/node/watch/exec_luac.js\";\n        String root = \"/home/hanks/work/opensource/api_luanroid/lua\";\n        String outDir = \"/home/hanks/work/opensource/api_luanroid/plugin\";\n        String updateJSON = \"nodejs /home/hanks/work/opensource/LuaJAndroid/script/node/watch/update_plugin_info.js\";\n        String OS = System.getProperty(\"os.name\").toLowerCase();\n        if (OS.contains(\"windows\")){\n            compileLua = \"node D:\\\\work\\\\opensource\\\\hydrogenApp\\\\script\\\\node\\\\watch\\\\exec_luac.js\";\n            root = \"D:\\\\work\\\\opensource\\\\api_luanroid\\\\lua\";\n            outDir = \"D:\\\\work\\\\opensource\\\\api_luanroid\\\\plugin\";\n            updateJSON = \"node D:\\\\work\\\\opensource\\\\hydrogenApp\\\\script\\\\node\\\\watch\\\\update_plugin_info.js\";\n        }\n\n        execCMD(compileLua);\n\n        File[] files = new File(root).listFiles();\n        for (File file : files) {\n            if (!file.isDirectory()) {\n                continue;\n            }\n            File[] childFiles = file.listFiles();\n            boolean isPlugin = false;\n            for (File childFile : childFiles) {\n                if (childFile.getName().equals(\"info.json\")) {\n                    isPlugin = true;\n                    break;\n                }\n            }\n            if (isPlugin) {\n                //创建文件输出对象out,提示:注意中文支持\n                FileOutputStream out = new FileOutputStream(outDir + File.separator + file.getName() + \".zip\");\n                //將文件輸出ZIP输出流接起来\n                ZipOutputStream zos = new ZipOutputStream(out);\n                zos.setLevel(BEST_COMPRESSION);\n                zip(zos, file.getAbsoluteFile(), file.getName());\n                zos.flush();\n                zos.close();\n            }\n        }\n\n        execCMD(updateJSON);\n    }\n\n}"
  },
  {
    "path": "script/lua/buildfile.lua",
    "content": "local path,outPath = ...\n\n-- print(path, outPath)\n\nif path==nil or outPath == nil then\n  return\nend\n\nlocal str,err = loadfile(path)\nif err then\n  return\nend\nlocal success, code= pcall(string.dump,str,true)\nif success then\n  f=io.open(outPath,'wb')\n  f:write(code)\n  f:close()\n  return\nend\n"
  },
  {
    "path": "script/node/watch/build_lua_main_dir.js",
    "content": "// 功能： 编译 lua\n\nvar fs = require('fs');\nvar path = require('path');\nvar shelljs = require('shelljs/global');\nconst os = require('os');\n\n\nvar buildfilePath = '/home/hanks/work/opensource/LuaJAndroid/script/lua/buildfile.lua'\n\nif (os.platform() == 'win32') {\n    buildfilePath = \"D:\\\\work\\\\opensource\\\\LuaJAndroid\\\\script\\\\lua\\\\buildfile.lua\";\n}\n\nfunction build(file){\n  var stats = fs.statSync(file);\n  if(stats.isDirectory()){\n    fs.readdir(file, function (err, plugins) {\n      plugins.forEach(function (p) {\n        build(path.join(file,p))\n      });\n    });\n  }else {\n\n    if(!file.endsWith('.lua')) return;\n    var dir = path.dirname('file');\n    cd(dir)\n    var outPath = file + 'c'\n    var cmd = 'lua ' +buildfilePath + ' ' + file  + ' ' + outPath;\n    console.log(cmd);\n    exec(cmd);\n    rm(file)\n    mv(outPath, file)\n    console.log('-----');\n  }\n}\nfunction buildDir(sourceDir,pluginRoot){\n  rm('-rf', pluginRoot);\n  cp('-R', sourceDir, pluginRoot);\n  build(pluginRoot);\n}\n\nif (os.platform() == 'win32') {\n    buildDir(\"D:\\\\work\\\\opensource\\\\LuaJAndroid\\\\lua_main\",\"D:\\\\work\\\\opensource\\\\LuaJAndroid\\\\sample\\\\src\\\\main\\\\assets\\\\lua\")\n}else{\n    buildDir(\"/home/hanks/work/opensource/LuaJAndroid/lua_main\",\"/home/hanks/work/opensource/LuaJAndroid/sample/src/main/assets/lua\")\n}\n"
  },
  {
    "path": "script/node/watch/exec_luac.js",
    "content": "// 功能： 编译 lua\n\nvar fs = require('fs');\nvar path = require('path');\nvar shelljs = require('shelljs/global');\nconst os = require('os');\n\n\nvar buildfilePath = '/home/hanks/work/opensource/hydrogenApp/script/lua/buildfile.lua'\n\nif (os.platform() == 'win32') {\n    buildfilePath = \"D:\\\\work\\\\opensource\\\\hydrogenApp\\\\script\\\\lua\\\\buildfile.lua\";\n}\n\nfunction build(file){\n  var stats = fs.statSync(file);\n  if(stats.isDirectory()){\n    fs.readdir(file, function (err, plugins) {\n      plugins.forEach(function (p) {\n        build(path.join(file,p))\n      });\n    });\n  }else {\n\n    if(!file.endsWith('.lua')) return;\n    var dir = path.dirname('file');\n    cd(dir)\n    var outPath = file + 'c'\n    var cmd = 'lua ' +buildfilePath + ' ' + file  + ' ' + outPath;\n    console.log(cmd);\n    exec(cmd);\n    rm(file)\n    mv(outPath, file)\n    console.log('-----');\n  }\n}\nfunction buildDir(sourceDir,pluginRoot){\n  rm('-rf', pluginRoot);\n  cp('-R', sourceDir, pluginRoot);\n  build(pluginRoot);\n}\n\nif (os.platform() == 'win32') {\n    buildDir(\"D:\\\\work\\\\opensource\\\\hydrogenApp\\\\lua_main\",\"D:\\\\work\\\\opensource\\\\hydrogenApp\\\\sample\\\\src\\\\main\\\\assets\\\\lua\")\n    buildDir(\"D:\\\\work\\\\opensource\\\\hydrogenApp\\\\lua\",\"D:\\\\work\\\\opensource\\\\api_luanroid\\\\lua\")\n}else{\n    buildDir(\"/home/hanks/work/opensource/hydrogenApp/lua_main\",\"/home/hanks/work/opensource/hydrogenApp/sample/src/main/assets/lua\")\n    buildDir(\"/home/hanks/work/opensource/hydrogenApp/lua\",\"/home/hanks/work/opensource/api_luanroid/lua\")\n}\n"
  },
  {
    "path": "script/node/watch/package.json",
    "content": "{\n  \"name\": \"watch\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"watch.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"archiver\": \"^1.3.0\",\n    \"chokidar\": \"^1.7.0\",\n    \"fs\": \"0.0.1-security\",\n    \"shelljs\": \"^0.7.8\"\n  }\n}\n"
  },
  {
    "path": "script/node/watch/update_plugin_info.js",
    "content": "var fs = require('fs');\nvar path = require('path');\nvar archiver = require('archiver');\nconst os = require('os');\n\nvar root = \"/home/hanks/work/opensource/hydrogenApp/lua\";\nvar apiFile = \"/home/hanks/work/opensource/api_luanroid/api/plugins\";\n\nif (os.platform() == 'win32') {\n      root = \"D:\\\\work\\\\opensource\\\\hydrogenApp\\\\lua\";\n      apiFile = \"D:\\\\work\\\\opensource\\\\api_luanroid\\\\api\\\\plugins\";\n}\n\nvar res = {data:[]};\n\nvar plugins = fs.readdirSync(root);\nfor (var j = 0; j < plugins.length; j++) {\n    var pluginDir = path.join(root,plugins[j]);\n    var files = fs.readdirSync(pluginDir);\n    for (var i = 0; i < files.length; i++) {\n       if(files[i] != 'info.json') continue;\n       var text = fs.readFileSync(path.join(pluginDir,files[i]),'utf8');\n       var json = JSON.parse(text);\n       if (json.private && json.private == true){\n            continue;\n       }\n       json.download = 'https://coding.net/u/zhangyuhan/p/api_luanroid/git/raw/master/plugin/' + plugins[j] + '.zip';\n       res.data.push(json);\n    }\n}\n// 生成 json\nvar apiData = JSON.stringify(res);\nconsole.log(apiData);\nfs.writeFileSync(apiFile,apiData,'utf8');\n\n"
  },
  {
    "path": "script/node/watch/watch.js",
    "content": "var chokidar = require('chokidar');\nvar shelljs = require('shelljs');\nconst os = require('os');\nvar fs = require('fs');\nvar path = require('path');\n\nvar watchDir = '/Users/zhanks/work/opensource/LuajAndroid/lua';\nvar pushDir = '/Users/zhanks/work/opensource/LuajAndroid/lua/*'\nif (os.platform() == 'win32') {\n  watchDir = 'D:\\\\work\\\\opensource\\\\LuaJAndroid\\\\lua';\n  pushDir = 'D:\\\\work\\\\opensource\\\\LuaJAndroid\\\\lua';\n}\nconsole.log(watchDir);\n\nfunction pushFiles(changedFile) {\n\tvar pushPath = pushDir\n\tvar parent = path.dirname(changedFile);\n\tvar i=0;\n\tvar folderName = ''\n\twhile (parent != watchDir && path.dirname(parent) != watchDir){\n\t\tparent =  path.dirname(parent);\n\t\tif(++i > 5){\n\t\t\tbreak;\n\t\t}\n\t}\n\tpushPath = parent;\n\tfolderName = path.basename(parent);\n\n\tvar cmd = 'adb push ' + pushPath + '  /sdcard/Android/data/pub.hanks.sample/files/LLLLLua/' + folderName \n\tconsole.log(cmd)\n\tshelljs.exec(cmd);\n}\n\nchokidar.watch(watchDir)\n\t.on('add', changedFile=>{\n\t\t//pushFiles(changedFile)\n\t})\n\t.on('change', changedFile =>{\n\t\tpushFiles(changedFile)\n\t});\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':hydrogen-library', ':sample'\n"
  }
]